Migrated most of the example and library to new design.

This commit is contained in:
2015-03-31 14:50:20 +02:00
parent 449720c99e
commit 060a2bb952
125 changed files with 2401 additions and 1791 deletions

View File

@@ -7,13 +7,11 @@ class
DEMO_BASIC
inherit
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [DEMO_BASIC_EXECUTION]
redefine
initialize
end
SHARED_HTML_ENCODER
create
make_and_launch
@@ -26,210 +24,4 @@ feature {NONE} -- Initialization
set_service_option ("verbose", True)
end
feature -- Credentials
is_known_login (a_login: READABLE_STRING_GENERAL): BOOLEAN
-- Is `a_login' a known username?
do
Result := valid_credentials.has (a_login)
end
is_valid_credential (a_login: READABLE_STRING_GENERAL; a_password: detachable READABLE_STRING_GENERAL): BOOLEAN
-- Is `a_login:a_password' a valid credential?
do
if
a_password /= Void and
attached valid_credentials.item (a_login) as l_passwd
then
Result := a_password.is_case_insensitive_equal (l_passwd)
end
ensure
Result implies is_known_login (a_login)
end
demo_credential: STRING_32
-- First valid known credential display for demo in dialog.
do
valid_credentials.start
create Result.make_from_string_general (valid_credentials.key_for_iteration)
Result.append_character (':')
Result.append (valid_credentials.item_for_iteration)
end
valid_credentials: STRING_TABLE [READABLE_STRING_32]
-- Password indexed by login.
once
create Result.make_caseless (3)
Result.force ("world", "eiffel")
Result.force ("bar", "foo")
Result.force ("password", "user")
ensure
not Result.is_empty
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
local
auth: HTTP_AUTHORIZATION
l_authenticated_username: detachable READABLE_STRING_32
l_invalid_credential: BOOLEAN
do
if attached req.http_authorization as l_http_auth then
create auth.make (l_http_auth)
if attached auth.login as l_login and then is_valid_credential (l_login, auth.password) then
l_authenticated_username := auth.login
else
l_invalid_credential := True
end
end
if l_invalid_credential then
handle_unauthorized ("ERROR: Invalid credential", req, res)
else
if l_authenticated_username /= Void then
handle_authenticated (l_authenticated_username, req, res)
elseif req.path_info.same_string_general ("/login") then
handle_unauthorized ("Please provide credential ...", req, res)
elseif req.path_info.starts_with_general ("/protected/") then
-- any "/protected/*" url
handle_unauthorized ("Protected area, please sign in before", req, res)
else
handle_anonymous (req, res)
end
end
end
handle_authenticated (a_username: READABLE_STRING_32; req: WSF_REQUEST; res: WSF_RESPONSE)
-- User `a_username' is authenticated, execute request `req' with response `res'.
require
valid_username: not a_username.is_empty
known_username: is_known_login (a_username)
local
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_empty
append_html_header (req, s)
s.append ("<p>The authenticated user is <strong>")
s.append (html_encoder.general_encoded_string (a_username))
s.append ("</strong> ...</p>")
append_html_menu (a_username, req, s)
append_html_logout (a_username, req, s)
append_html_footer (req, s)
create page.make
page.set_body (s)
res.send (page)
end
handle_anonymous (req: WSF_REQUEST; res: WSF_RESPONSE)
-- No user is authenticated, execute request `req' with response `res'.
local
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_empty
append_html_header (req, s)
s.append ("Anonymous visitor ...<br/>")
append_html_login (req, s)
append_html_menu (Void, req, s)
append_html_footer (req, s)
create page.make
page.set_body (s)
res.send (page)
end
handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Restricted page, authenticated user is required.
-- Send `a_description' as part of the response.
local
h: HTTP_HEADER
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_from_string (a_description)
append_html_login (req, s)
append_html_menu (Void, req, s)
append_html_footer (req, s)
create page.make
page.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
page.header.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate,
"Basic realm=%"Please enter a valid username and password (demo [" + html_encoder.encoded_string (demo_credential) + "])%""
--| warning: for this example: a valid credential is provided in the message, of course that for real application.
)
page.set_body (s)
res.send (page)
end
feature -- Helper
append_html_header (req: WSF_REQUEST; s: STRING)
-- Append header paragraph to `s'.
do
s.append ("<p>The current page is " + html_encoder.encoded_string (req.path_info) + "</p>")
end
append_html_menu (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
-- Append menu to `s'.
-- when an user is authenticated, `a_username' is attached.
do
if a_username /= Void then
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">Your account</a> (displayed only is user is authenticated!)</li>")
end
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">home</a></li>")
s.append ("<li><a href=%""+ req.script_url ("/public/area") +"%">public area</a></li>")
s.append ("<li><a href=%""+ req.script_url ("/protected/area") +"%">protected area</a></li>")
end
append_html_login (req: WSF_REQUEST; s: STRING)
-- Append login link to `s'.
do
s.append ("<li><a href=%""+ req.script_url ("/login") +"%">sign in</a></li>")
end
append_html_logout (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
-- Append logout link to `s'.
local
l_logout_url: STRING
do
l_logout_url := req.absolute_script_url ("/login")
l_logout_url.replace_substring_all ("://", "://_@") -- Hack to clear http authorization, i.e connect with bad username "_".
s.append ("<li><a href=%""+ l_logout_url +"%">logout</a></li>")
end
append_html_footer (req: WSF_REQUEST; s: STRING)
-- Append html footer to `s'.
local
hauth: HTTP_AUTHORIZATION
do
s.append ("<hr/>")
if attached req.http_authorization as l_http_authorization then
s.append ("Has <em>Authorization:</em> header: ")
create hauth.make (req.http_authorization)
if attached hauth.login as l_login then
s.append (" login=<strong>" + html_encoder.encoded_string (l_login)+ "</strong>")
end
if attached hauth.password as l_password then
s.append (" password=<strong>" + html_encoder.encoded_string (l_password)+ "</strong>")
end
s.append ("<br/>")
end
if attached req.raw_header_data as l_header then
-- Append the raw header data for information
s.append ("Raw header data:")
s.append ("<pre>")
s.append (l_header)
s.append ("</pre>")
end
end
end

View File

@@ -0,0 +1,226 @@
note
description : "simple application root class"
date : "$Date$"
revision : "$Revision$"
class
DEMO_BASIC_EXECUTION
inherit
WSF_EXECUTION
SHARED_HTML_ENCODER
create
make
feature -- Credentials
is_known_login (a_login: READABLE_STRING_GENERAL): BOOLEAN
-- Is `a_login' a known username?
do
Result := valid_credentials.has (a_login)
end
is_valid_credential (a_login: READABLE_STRING_GENERAL; a_password: detachable READABLE_STRING_GENERAL): BOOLEAN
-- Is `a_login:a_password' a valid credential?
do
if
a_password /= Void and
attached valid_credentials.item (a_login) as l_passwd
then
Result := a_password.is_case_insensitive_equal (l_passwd)
end
ensure
Result implies is_known_login (a_login)
end
demo_credential: STRING_32
-- First valid known credential display for demo in dialog.
do
valid_credentials.start
create Result.make_from_string_general (valid_credentials.key_for_iteration)
Result.append_character (':')
Result.append (valid_credentials.item_for_iteration)
end
valid_credentials: STRING_TABLE [READABLE_STRING_32]
-- Password indexed by login.
once
create Result.make_caseless (3)
Result.force ("world", "eiffel")
Result.force ("bar", "foo")
Result.force ("password", "user")
ensure
not Result.is_empty
end
feature -- Basic operations
execute
-- <Precursor>
local
auth: HTTP_AUTHORIZATION
l_authenticated_username: detachable READABLE_STRING_32
l_invalid_credential: BOOLEAN
req: WSF_REQUEST
res: WSF_RESPONSE
do
req := request
res := response
if attached req.http_authorization as l_http_auth then
create auth.make (l_http_auth)
if attached auth.login as l_login and then is_valid_credential (l_login, auth.password) then
l_authenticated_username := auth.login
else
l_invalid_credential := True
end
end
if l_invalid_credential then
handle_unauthorized ("ERROR: Invalid credential", req, res)
else
if l_authenticated_username /= Void then
handle_authenticated (l_authenticated_username, req, res)
elseif req.path_info.same_string_general ("/login") then
handle_unauthorized ("Please provide credential ...", req, res)
elseif req.path_info.starts_with_general ("/protected/") then
-- any "/protected/*" url
handle_unauthorized ("Protected area, please sign in before", req, res)
else
handle_anonymous (req, res)
end
end
end
handle_authenticated (a_username: READABLE_STRING_32; req: WSF_REQUEST; res: WSF_RESPONSE)
-- User `a_username' is authenticated, execute request `req' with response `res'.
require
valid_username: not a_username.is_empty
known_username: is_known_login (a_username)
local
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_empty
append_html_header (req, s)
s.append ("<p>The authenticated user is <strong>")
s.append (html_encoder.general_encoded_string (a_username))
s.append ("</strong> ...</p>")
append_html_menu (a_username, req, s)
append_html_logout (a_username, req, s)
append_html_footer (req, s)
create page.make
page.set_body (s)
res.send (page)
end
handle_anonymous (req: WSF_REQUEST; res: WSF_RESPONSE)
-- No user is authenticated, execute request `req' with response `res'.
local
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_empty
append_html_header (req, s)
s.append ("Anonymous visitor ...<br/>")
append_html_login (req, s)
append_html_menu (Void, req, s)
append_html_footer (req, s)
create page.make
page.set_body (s)
res.send (page)
end
handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Restricted page, authenticated user is required.
-- Send `a_description' as part of the response.
local
s: STRING
page: WSF_HTML_PAGE_RESPONSE
do
create s.make_from_string (a_description)
append_html_login (req, s)
append_html_menu (Void, req, s)
append_html_footer (req, s)
create page.make
page.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
page.header.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate,
"Basic realm=%"Please enter a valid username and password (demo [" + html_encoder.encoded_string (demo_credential) + "])%""
--| warning: for this example: a valid credential is provided in the message, of course that for real application.
)
page.set_body (s)
res.send (page)
end
feature -- Helper
append_html_header (req: WSF_REQUEST; s: STRING)
-- Append header paragraph to `s'.
do
s.append ("<p>The current page is " + html_encoder.encoded_string (req.path_info) + "</p>")
end
append_html_menu (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
-- Append menu to `s'.
-- when an user is authenticated, `a_username' is attached.
do
if a_username /= Void then
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">Your account</a> (displayed only is user is authenticated!)</li>")
end
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">home</a></li>")
s.append ("<li><a href=%""+ req.script_url ("/public/area") +"%">public area</a></li>")
s.append ("<li><a href=%""+ req.script_url ("/protected/area") +"%">protected area</a></li>")
end
append_html_login (req: WSF_REQUEST; s: STRING)
-- Append login link to `s'.
do
s.append ("<li><a href=%""+ req.script_url ("/login") +"%">sign in</a></li>")
end
append_html_logout (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
-- Append logout link to `s'.
local
l_logout_url: STRING
do
l_logout_url := req.absolute_script_url ("/login")
l_logout_url.replace_substring_all ("://", "://_@") -- Hack to clear http authorization, i.e connect with bad username "_".
s.append ("<li><a href=%""+ l_logout_url +"%">logout</a></li>")
end
append_html_footer (req: WSF_REQUEST; s: STRING)
-- Append html footer to `s'.
local
hauth: HTTP_AUTHORIZATION
do
s.append ("<hr/>")
if attached req.http_authorization as l_http_authorization then
s.append ("Has <em>Authorization:</em> header: ")
create hauth.make (req.http_authorization)
if attached hauth.login as l_login then
s.append (" login=<strong>" + html_encoder.encoded_string (l_login)+ "</strong>")
end
if attached hauth.password as l_password then
s.append (" password=<strong>" + html_encoder.encoded_string (l_password)+ "</strong>")
end
s.append ("<br/>")
end
if attached req.raw_header_data as l_header then
-- Append the raw header data for information
s.append ("Raw header data:")
s.append ("<pre>")
s.append (l_header)
s.append ("</pre>")
end
end
end

View File

@@ -26,23 +26,6 @@ feature {NONE} -- Implementation
create connector.make_with_base (a_base_url)
end
-- make_with_callback (a_callback: PROCEDURE [ANY, TUPLE [req: WGI_REQUEST; res: WGI_RESPONSE]])
-- -- Initialize `Current'.
-- do
-- make_custom_with_callback (a_callback, Void)
-- end
-- make_custom_with_callback (a_callback: PROCEDURE [ANY, TUPLE [req: WGI_REQUEST; res: WGI_RESPONSE]]; a_base_url: detachable STRING)
-- -- Initialize `Current'.
-- require
-- base_url_starts_with_slash: (a_base_url /= Void and then not a_base_url.is_empty) implies a_base_url.starts_with ("/")
-- local
-- app: WGI_AGENT_SERVICE
-- do
-- create app.make (a_callback)
-- make_custom (app, a_base_url)
-- end
feature -- Access
connector: WGI_NINO_CONNECTOR [G]

View File

@@ -17,16 +17,27 @@ feature {NONE} -- Initialization
make
-- Initialize `Current'.
local
conn: WGI_HTTPD_CONNECTOR [APP_WSF_EXECUTION]
conn: WGI_STANDALONE_CONNECTOR [APP_WSF_EXECUTION]
do
print ("Starting httpd server ...%N")
create conn.make
conn.on_launched_actions.extend (agent on_launched)
conn.set_port_number (9090)
conn.set_max_concurrent_connections (100)
conn.launch
end
on_launched (conn: WGI_STANDALONE_CONNECTOR [WGI_EXECUTION])
do
print ("Server listening on port " + conn.port.out + "%N")
end
on_stopped (conn: WGI_STANDALONE_CONNECTOR [WGI_EXECUTION])
do
print ("Server terminated%N")
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -19,14 +19,19 @@ feature {NONE} -- Initialization
reset
do
has_error := False
version := Void
remote_info := Void
reset_request
has_error := False
if attached internal_client_socket as l_sock then
l_sock.cleanup
end
internal_client_socket := Void
end
reset_request
do
version := Void
remote_info := Void
-- FIXME: optimize to just wipe_out if needed
create method.make_empty
@@ -34,6 +39,7 @@ feature {NONE} -- Initialization
create request_header.make_empty
create request_header_map.make (10)
keep_alive_enabled := False
end
feature -- Status report
@@ -79,6 +85,24 @@ feature -- Access
remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER]
-- Information related to remote client
keep_alive_enabled: BOOLEAN
-- Inside a persistent connection?
is_http_version_1_0: BOOLEAN
do
Result := not attached version as v or else v.same_string ("HTTP/1.0")
end
is_http_version_1_1: BOOLEAN
do
Result := not attached version as v or else v.same_string ("HTTP/1.1")
end
is_http_version_2: BOOLEAN
do
Result := not attached version as v or else v.same_string ("HTTP/2.0")
end
feature -- Settings
is_verbose: BOOLEAN
@@ -93,6 +117,7 @@ feature -- Change
set_is_verbose (b: BOOLEAN)
do
is_verbose := b
print ("set_is_verbose " + b.out + "%N")
end
feature -- Execution
@@ -118,6 +143,33 @@ feature -- Execution
end
execute
require
is_connected: is_connected
local
l_socket: like client_socket
l_exit: BOOLEAN
n: INTEGER
do
l_socket := client_socket
check
socket_attached: l_socket /= Void
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
end
from
-- Process persistent connection as long the socket is not closed.
n := 0
until
l_exit
loop
n := n + 1
-- FIXME: it seems to be called one more time, mostly to see this is done.
execute_request
l_exit := has_error or l_socket.is_closed or not l_socket.is_open_read or not keep_alive_enabled
reset_request
end
end
execute_request
require
is_connected: is_connected
local
@@ -132,14 +184,15 @@ feature -- Execution
end
if l_socket.is_closed then
debug ("dbglog")
dbglog (generator + ".execute {socket is Closed!}")
dbglog (generator + ".execute_request {socket is Closed!}")
end
else
debug ("dbglog")
dbglog (generator + ".execute socket=" + l_socket.descriptor.out + " ENTER")
dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER")
end
from until l_continue loop
if l_socket.ready_for_reading then
if l_socket.try_ready_for_reading then
-- ready_for_reading then
l_continue := True
create l_remote_info
if attached l_socket.peer_address as l_addr then
@@ -150,7 +203,11 @@ feature -- Execution
end
analyze_request_message (l_socket)
else
log (generator + ".execute socket=" + l_socket.descriptor.out + "} WAITING")
has_error := True
l_continue := True
debug ("dbglog")
dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + "} WAITING")
end
end
end
@@ -164,7 +221,7 @@ feature -- Execution
process_request (l_socket)
end
debug ("dbglog")
dbglog (generator + ".execute {" + l_socket.descriptor.out + "} LEAVE")
dbglog (generator + ".execute_request {" + l_socket.descriptor.out + "} LEAVE")
end
end
end
@@ -243,6 +300,22 @@ feature -- Parsing
line := next_line (a_socket)
end
end
if not {HTTPD_SERVER}.is_persistent_connection_supported then
keep_alive_enabled := False
elseif is_http_version_1_0 then
keep_alive_enabled := attached request_header_map.item ("Connection") as l_connection and then
l_connection.is_case_insensitive_equal_general ("keep-alive")
else
-- By default HTTP:1/1 support persistent connection.
if
attached request_header_map.item ("Connection") as l_connection and then
l_connection.is_case_insensitive_equal_general ("close")
then
keep_alive_enabled := False
else
keep_alive_enabled := True
end
end
end
end
@@ -251,7 +324,7 @@ feature -- Parsing
require
valid_line: line /= Void and then not line.is_empty
local
pos, next_pos: INTEGER
n, pos, next_pos: INTEGER
do
if is_verbose then
log ("%N## Parse HTTP request line ##")
@@ -261,7 +334,11 @@ feature -- Parsing
method := line.substring (1, pos - 1)
next_pos := line.index_of (' ', pos + 1)
uri := line.substring (pos + 1, next_pos - 1)
version := line.substring (next_pos + 1, line.count)
n := line.count
if line[n] = '%R' then
n := n - 1
end
version := line.substring (next_pos + 1, n)
has_error := method.is_empty
end
@@ -269,11 +346,18 @@ feature -- Parsing
-- Next line fetched from `a_socket' is available.
require
is_readable: a_socket.is_open_read
local
retried: BOOLEAN
do
if a_socket.socket_ok then
if retried then
Result := Void
elseif a_socket.socket_ok then
a_socket.read_line_thread_aware
Result := a_socket.last_string
end
rescue
retried := True
retry
end
feature -- Output

View File

@@ -58,6 +58,19 @@ feature -- Access
factory: separate HTTPD_REQUEST_HANDLER_FACTORY
is_persistent_connection_supported: BOOLEAN = False
-- Is persistent connection supported?
--| For now, disabled during dev.
feature -- Callbacks
observer: detachable separate HTTPD_SERVER_OBSERVER
set_observer (obs: like observer)
do
observer := obs
end
feature -- Access: listening
port: INTEGER
@@ -91,22 +104,10 @@ feature -- Execution
end
is_shutdown_requested := False
listen
is_terminated := True
on_terminated
end
on_terminated
require
is_terminated
do
if is_terminated then
log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N")
end
if attached output as o then
o.flush
o.close
end
end
shutdown_server
do
debug ("dbglog")
@@ -251,8 +252,12 @@ feature -- Event
require
not_launched: not is_launched
do
-- print ("port=" + a_port.out + "%N")
is_launched := True
port := a_port
if attached observer as obs then
observer_on_launched (obs, a_port)
end
ensure
is_launched: is_launched
end
@@ -262,10 +267,43 @@ feature -- Event
require
is_launched: is_launched
do
is_launched := False
is_terminated := True
ensure
stopped: not is_launched
if attached observer as obs then
observer_on_stopped (obs)
end
end
on_terminated
-- Server terminated
require
is_terminated
do
if is_terminated and is_verbose then
log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N")
end
if attached output as o then
o.flush
o.close
end
if attached observer as obs then
observer_on_terminated (obs)
end
end
feature {NONE} -- Separate event
observer_on_launched (obs: attached like observer; a_port: INTEGER)
do
obs.on_launched (a_port)
end
observer_on_stopped (obs: attached like observer)
do
obs.on_stopped
end
observer_on_terminated (obs: attached like observer)
do
obs.on_terminated
end
feature -- Configuration change

View File

@@ -0,0 +1,24 @@
note
description: "Summary description for {HTTPD_SERVER_OBSERVER}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
HTTPD_SERVER_OBSERVER
feature -- Event
on_launched (a_port: INTEGER)
deferred
end
on_stopped
deferred
end
on_terminated
deferred
end
end

View File

@@ -26,9 +26,14 @@ feature {NONE} -- Initialization
do
make
connector := conn
-- if conn /= Void then
-- set_is_verbose (is_connector_verbose (conn))
-- end
end
connector: detachable separate WGI_HTTPD_CONNECTOR [G]
feature -- Access
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
base: detachable IMMUTABLE_STRING_8
do
@@ -39,11 +44,18 @@ feature {NONE} -- Initialization
end
end
connector_base (conn: separate WGI_HTTPD_CONNECTOR [G]): detachable separate READABLE_STRING_8
feature -- SCOOP helpers
connector_base (conn: separate WGI_STANDALONE_CONNECTOR [G]): detachable separate READABLE_STRING_8
do
Result := conn.base
end
is_connector_verbose (conn: separate WGI_STANDALONE_CONNECTOR [G]): BOOLEAN
do
Result := conn.is_verbose
end
feature -- Request processing
process_request (a_socket: HTTPD_STREAM_SOCKET)
@@ -53,14 +65,14 @@ feature -- Request processing
l_output: WGI_OUTPUT_STREAM
l_error: WGI_ERROR_STREAM
req: WGI_REQUEST_FROM_TABLE
res: detachable WGI_HTTPD_RESPONSE_STREAM
res: detachable WGI_STANDALONE_RESPONSE_STREAM
exec: detachable WGI_EXECUTION
retried: BOOLEAN
do
if not retried then
create {WGI_HTTPD_INPUT_STREAM} l_input.make (a_socket)
create {WGI_HTTPD_OUTPUT_STREAM} l_output.make (a_socket)
create {WGI_HTTPD_ERROR_STREAM} l_error.make_stderr (a_socket.descriptor.out)
create {WGI_STANDALONE_INPUT_STREAM} l_input.make (a_socket)
create {WGI_STANDALONE_OUTPUT_STREAM} l_output.make (a_socket)
create {WGI_STANDALONE_ERROR_STREAM} l_error.make_stderr (a_socket.descriptor.out)
create req.make (httpd_environment (a_socket), l_input, connector)
create res.make (l_output, l_error)

View File

@@ -12,7 +12,7 @@ inherit
feature -- Access
connector: detachable separate WGI_HTTPD_CONNECTOR [G]
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
feature -- Element change

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {WGI_HTTPD_CONNECTOR}."
description: "Summary description for {WGI_STANDALONE_CONNECTOR}."
author: ""
todo: "[
Check if server and configuration has to be 'separate' ?
@@ -11,7 +11,7 @@ note
revision: "$Revision$"
class
WGI_HTTPD_CONNECTOR [G -> WGI_EXECUTION create make end]
WGI_STANDALONE_CONNECTOR [G -> WGI_EXECUTION create make end]
inherit
WGI_CONNECTOR
@@ -28,14 +28,15 @@ feature {NONE} -- Initialization
do
-- Callbacks
create on_launched_actions
create on_stopped_actions
-- Server
create fac
create server.make (fac)
create observer
configuration := server_configuration (server)
controller := server_controller (server)
set_factory_connector (Current, fac)
initialize_server (server)
end
make_with_base (a_base: like base)
@@ -46,11 +47,23 @@ feature {NONE} -- Initialization
set_base (a_base)
end
set_factory_connector (conn: detachable separate WGI_HTTPD_CONNECTOR [G]; fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G])
initialize_server (a_server: like server)
do
a_server.set_observer (observer)
end
feature {NONE} -- Separate helper
set_factory_connector (conn: detachable separate WGI_STANDALONE_CONNECTOR [G]; fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G])
do
fac.set_connector (conn)
end
server_configuration (a_server: like server): like configuration
do
Result := a_server.configuration
end
feature -- Access
name: STRING_8 = "httpd"
@@ -63,12 +76,11 @@ feature -- Access
server: separate HTTPD_SERVER
configuration: separate HTTPD_CONFIGURATION
controller: separate HTTPD_CONTROLLER
server_configuration (a_server: like server): like configuration
do
Result := a_server.configuration
end
observer: separate WGI_STANDALONE_SERVER_OBSERVER
configuration: separate HTTPD_CONFIGURATION
feature -- Access
@@ -82,17 +94,17 @@ feature -- Status report
port: INTEGER
-- Listening port.
--| 0: not launched
--| 0: not launched
is_verbose: BOOLEAN
-- Is verbose?
feature -- Callbacks
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_CONNECTOR]]
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]]]
-- Actions triggered when launched
on_stopped_actions: ACTION_SEQUENCE [TUPLE [WGI_CONNECTOR]]
-- Actions triggered when stopped
feature -- Element change
feature -- Event
on_launched (a_port: INTEGER)
-- Server launched
@@ -102,14 +114,6 @@ feature -- Element change
on_launched_actions.call ([Current])
end
on_stopped
-- Server stopped
do
on_stopped_actions.call ([Current])
launched := False
port := 0
end
feature -- Element change
set_base (b: like base)
@@ -154,6 +158,7 @@ feature {NONE} -- Implementation
set_is_verbose_on_configuration (b: BOOLEAN; cfg: like configuration)
do
is_verbose := b
cfg.set_is_verbose (b)
end
@@ -164,6 +169,29 @@ feature -- Server
launched := False
port := 0
launch_server (server)
on_server_started (observer)
end
shutdown_server
do
if launched then
-- FIXME jfiat [2015/03/27] : prevent multiple calls (otherwise it hangs)
separate_shutdown_server_on_controller (controller)
end
end
server_controller (a_server: like server): separate HTTPD_CONTROLLER
do
Result := a_server.controller
end
on_server_started (obs: like observer)
require
obs.started
do
if obs.port > 0 then
on_launched (obs.port)
end
end
configure_server (a_configuration: like configuration)
@@ -181,6 +209,19 @@ feature -- Server
a_server.launch
end
feature {NONE} -- Implementation
separate_server_terminated (a_server: like server): BOOLEAN
do
Result := a_server.is_terminated
end
separate_shutdown_server_on_controller (a_controller: separate HTTPD_CONTROLLER)
do
a_controller.shutdown
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -1,12 +1,12 @@
note
description: "Summary description for WGI_HTTPD_ERROR_STREAM."
description: "Summary description for WGI_STANDALONE_ERROR_STREAM."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_ERROR_STREAM
WGI_STANDALONE_ERROR_STREAM
inherit
WGI_ERROR_STREAM
@@ -58,7 +58,7 @@ feature -- Error
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,12 +1,12 @@
note
description: "Summary description for {WGI_HTTPD_INPUT_STREAM}."
description: "Summary description for {WGI_STANDALONE_INPUT_STREAM}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_INPUT_STREAM
WGI_STANDALONE_INPUT_STREAM
inherit
WGI_INPUT_STREAM
@@ -22,7 +22,7 @@ feature {NONE} -- Initialization
set_source (a_source)
end
feature {WGI_HTTPD_CONNECTOR, WGI_SERVICE} -- Nino
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino
set_source (i: like source)
do

View File

@@ -1,12 +1,12 @@
note
description: "Summary description for {WGI_HTTPD_OUTPUT_STREAM}."
description: "Summary description for {WGI_STANDALONE_OUTPUT_STREAM}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_HTTPD_OUTPUT_STREAM
WGI_STANDALONE_OUTPUT_STREAM
inherit
WGI_OUTPUT_STREAM
@@ -26,7 +26,7 @@ feature {NONE} -- Initialization
set_target (a_target)
end
feature {WGI_HTTPD_CONNECTOR, WGI_SERVICE} -- Nino
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino
set_target (o: like target)
do

View File

@@ -7,7 +7,7 @@ note
revision: "$Revision$"
class
WGI_HTTPD_RESPONSE_STREAM
WGI_STANDALONE_RESPONSE_STREAM
inherit
WGI_RESPONSE_STREAM
@@ -27,9 +27,11 @@ feature -- Header output operation
o := output
o.put_string (a_text)
-- Nino does not support persistent connection for now
o.put_string ("Connection: close")
o.put_crlf
if not {HTTPD_SERVER}.is_persistent_connection_supported then
-- standalone does not support persistent connection for now
o.put_string ("Connection: close")
o.put_crlf
end
-- end of headers
o.put_crlf
@@ -38,7 +40,7 @@ feature -- Header output operation
end
;note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,28 +1,45 @@
note
description: "Summary description for {APP_WSF_HTTPD_REQUEST_HANDLER}."
description: "Summary description for {WGI_STANDALONE_SERVER_OBSERVER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_WSF_HTTPD_REQUEST_HANDLER
WGI_STANDALONE_SERVER_OBSERVER
inherit
WSF_HTTPD_REQUEST_HANDLER
HTTPD_SERVER_OBSERVER
create
make
feature -- Access
feature -- Execute
started: BOOLEAN
do_more (req: WGI_REQUEST; res: WGI_RESPONSE)
local
exec: WSF_EXECUTION
stopped: BOOLEAN
terminated: BOOLEAN
port: INTEGER
feature -- Event
on_launched (a_port: INTEGER)
do
create {APP_WSF_EXECUTION} exec.make (req, res)
exec.execute
started := True
port := a_port
end
on_stopped
do
stopped := True
end
on_terminated
do
port := 0
terminated := True
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="connector_httpd" uuid="49C99A6E-CCC1-4015-81F6-D7C43B592034" library_target="connector_httpd">
<target name="connector_httpd">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="connector_standalone" uuid="49C99A6E-CCC1-4015-81F6-D7C43B592034" library_target="connector_standalone">
<target name="connector_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option debug="false" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<debug name="dbglog" enabled="true"/>
<assertions precondition="true"/>
</option>
@@ -16,16 +16,14 @@
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
<library name="httpd" location="src\httpd\httpd-safe.ecf"/>
<cluster name="src" location=".\src\" recursive="true">
<file_rule>
<exclude>/httpd$</exclude>
</file_rule>
<library name="httpd" location="src\httpd\httpd-safe.ecf" readonly="false"/>
<cluster name="src" location=".\src\">
<cluster name="implementation" location="$|implementation\" hidden="true"/>
</cluster>
</target>
<target name="dev" extends="connector_httpd">
<target name="dev_scoop" extends="connector_standalone">
<root class="HTTPD_CONNECTOR_DEV" feature="make"/>
<option debug="false">
<option debug="true">
<debug name="dbglog" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" supplier_precondition="true"/>
</option>
@@ -33,10 +31,10 @@
<library name="wsf" location="..\..\..\wsf\wsf-safe.ecf" readonly="false"/>
<cluster name="dev" location="dev\" recursive="true"/>
</target>
<target name="dev_mt" extends="dev">
<target name="dev_mt" extends="dev_scoop">
<setting name="concurrency" value="thread"/>
</target>
<target name="dev_none" extends="dev">
<target name="dev_none" extends="dev_scoop">
<setting name="concurrency" value="none"/>
</target>
</system>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="connector_standalone" uuid="49C99A6E-CCC1-4015-81F6-D7C43B592034" library_target="connector_standalone">
<target name="connector_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="transitional">
<assertions precondition="true"/>
</option>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
<library name="http" location="..\..\..\..\network\protocol\http\http.ecf"/>
<library name="httpd" location="src\httpd\httpd.ecf" readonly="false"/>
<cluster name="src" location=".\src\">
<cluster name="implementation" location="$|implementation\" hidden="true"/>
</cluster>
</target>
</system>

View File

@@ -18,20 +18,13 @@ feature {NONE} -- Initialization
make
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")
(create {NINO_SERVICE}.make_custom (Current, "")).listen (port_number)
end
execute (req: WGI_REQUEST; res: WGI_RESPONSE)
do
res.set_status_code (200, Void)
res.put_header_text ("Content-Type: text/plain%R%N")
res.put_string ("Hello World!%N")
(create {NINO_SERVICE [HELLO_WORLD_EXECUTION]}.make_custom ("")).listen (port_number)
end
port_number: INTEGER = 8123
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2015, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,36 @@
note
description: "Summary description for {HELLO_WORLD_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HELLO_WORLD_EXECUTION
inherit
WGI_EXECUTION
create
make
feature {NONE} -- Initialization
execute
do
response.set_status_code (200, Void)
response.put_header_text ("Content-Type: text/plain%R%N")
response.put_string ("Hello World!%N")
end
note
copyright: "2011-2015, 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

@@ -1,15 +1,17 @@
note
description: "Summary description for {WSF_DEFAULT_RESPONSE_SERVICE}."
description: "Summary description for {WGI_EXECUTION_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_DEFAULT_RESPONSE_SERVICE [G -> WSF_EXECUTION create make end]
WGI_EXECUTION_FACTORY
inherit
WSF_DEFAULT_SERVICE [G]
feature -- Factory
WSF_RESPONSE_SERVICE [G]
execution (req: WGI_REQUEST; res: WGI_RESPONSE): WGI_EXECUTION
deferred
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"

View File

@@ -22,13 +22,13 @@ feature {NONE} -- Initialization
local
utf: UTF_CONVERTER
do
auth_type := req.auth_type
content_length := req.content_length
if attached req.content_type as ct then
content_type := ct.string
else
content_type := Void
end
auth_type := req.auth_type
gateway_interface := req.gateway_interface
path_info := req.path_info
path_translated := req.path_translated

View File

@@ -16,10 +16,10 @@ note
revision: "$Revision$"
class
WSF_OPENSHIFT_SERVICE_LAUNCHER
WSF_OPENSHIFT_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
WSF_NINO_SERVICE_LAUNCHER
WSF_NINO_SERVICE_LAUNCHER [G]
redefine
initialize
end
@@ -31,9 +31,7 @@ inherit
create
make,
make_and_launch,
make_callback,
make_callback_and_launch
make_and_launch
feature {NONE} -- Initialization
@@ -86,7 +84,7 @@ feature {NONE} -- Implementation
;note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_httpd" uuid="9BF2D71A-0986-4025-9C97-15B65F07C568" library_target="wsf_httpd">
<target name="wsf_httpd">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_standalone" uuid="9BF2D71A-0986-4025-9C97-15B65F07C568" library_target="wsf_standalone">
<target name="wsf_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
@@ -10,13 +10,13 @@
<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="connector_httpd" location="..\..\ewsgi\connectors\httpd\httpd-safe.ecf"/>
<library name="connector_standalone" location="..\..\ewsgi\connectors\standalone\standalone-safe.ecf"/>
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="error" location="..\..\..\utility\general\error\error-safe.ecf"/>
<library name="ewsgi" location="..\..\ewsgi\ewsgi-safe.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="wsf" location="..\wsf-safe.ecf"/>
<cluster name="wsf_httpd" location=".\httpd\" recursive="true"/>
<cluster name="wsf_standalone" location=".\standalone\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_standalone" uuid="9BF2D71A-0986-4025-9C97-15B65F07C568" library_target="wsf_standalone">
<target name="wsf_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="provisional">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="connector_standalone" location="..\..\ewsgi\connectors\standalone\standalone.ecf"/>
<library name="encoder" location="..\..\..\text\encoder\encoder.ecf" readonly="false"/>
<library name="error" location="..\..\..\utility\general\error\error.ecf"/>
<library name="ewsgi" location="..\..\ewsgi\ewsgi.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="wsf" location="..\wsf.ecf"/>
<cluster name="wsf_standalone" location=".\standalone\" recursive="true"/>
</target>
</system>

View File

@@ -8,8 +8,8 @@ note
The httpd default connector support options:
port: numeric such as 8099 (or equivalent string as "8099")
base: base_url (very specific to standalone server)
verbose: to display verbose output, useful for Nino
force_single_threaded: use only one thread, useful for Nino
verbose: to display verbose output, useful for standalone connector
force_single_threaded: use only one thread, useful for standalone connector
check WSF_SERVICE_LAUNCHER for more documentation
]"
@@ -17,7 +17,7 @@ note
revision: "$Revision$"
class
WSF_HTTPD_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
WSF_STANDALONE_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
WSF_SERVICE_LAUNCHER [G]
@@ -71,7 +71,6 @@ feature {NONE} -- Initialization
create conn.make
connector := conn
conn.on_launched_actions.extend (agent on_launched)
conn.on_stopped_actions.extend (agent on_stopped)
conn.set_base (base_url)
update_configuration (conn.configuration)
@@ -88,7 +87,6 @@ feature -- Execution
if attached server_name as l_server_name then
cfg.set_http_server_name (l_server_name)
end
-- conn.set_port_number (port_number)
cfg.http_server_port := port_number
end
@@ -102,7 +100,7 @@ feature -- Execution
conn.set_base (base_url)
debug ("nino")
if verbose then
io.error.put_string ("Launching Nino web server on port " + port_number.out)
io.error.put_string ("Launching standalone web server on port " + port_number.out)
if attached server_name as l_name then
io.error.put_string ("%N http://" + l_name + ":" + port_number.out + "/" + base_url + "%N")
else
@@ -116,24 +114,19 @@ feature -- Execution
feature -- Callback
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_CONNECTOR]]
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [G]]]
-- Actions triggered when launched
on_stopped_actions: ACTION_SEQUENCE [TUPLE [WGI_CONNECTOR]]
on_stopped_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [G]]]
-- Actions triggered when stopped
feature {NONE} -- Implementation
on_launched (conn: WGI_CONNECTOR)
on_launched (conn: WGI_STANDALONE_CONNECTOR [G])
do
on_launched_actions.call ([conn])
end
on_stopped (conn: WGI_CONNECTOR)
do
on_stopped_actions.call ([conn])
end
port_number: INTEGER
server_name: detachable READABLE_STRING_8
@@ -146,7 +139,7 @@ feature {NONE} -- Implementation
feature -- Status report
connector: WGI_HTTPD_CONNECTOR [G]
connector: WGI_STANDALONE_CONNECTOR [G]
-- Default connector
launchable: BOOLEAN

View File

@@ -1,24 +0,0 @@
note
description: "Summary description for {WSF_DEFAULT_RESPONSE_SERVICE}."
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_DEFAULT_RESPONSE_SERVICE
inherit
WSF_DEFAULT_SERVICE
WSF_RESPONSE_SERVICE
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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,13 +4,13 @@ note
revision: "$Revision$"
deferred class
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [G -> WSF_EXECUTION create make end]
inherit
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER]
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER [G]]
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,24 +0,0 @@
note
description: "Summary description for {WSF_DEFAULT_RESPONSE_SERVICE}."
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_DEFAULT_RESPONSE_SERVICE
inherit
WSF_DEFAULT_SERVICE
WSF_RESPONSE_SERVICE
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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

@@ -1,24 +0,0 @@
note
description: "Summary description for {WSF_DEFAULT_RESPONSE_SERVICE}."
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_DEFAULT_RESPONSE_SERVICE
inherit
WSF_DEFAULT_SERVICE
WSF_RESPONSE_SERVICE
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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,13 +4,13 @@ note
revision: "$Revision$"
deferred class
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [G -> WSF_EXECUTION create make end]
inherit
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER]
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER [G]]
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -5,19 +5,17 @@ note
revision: "$Revision$"
class
WSF_DEFAULT_SERVICE_LAUNCHER
WSF_DEFAULT_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
WSF_LIBFCGI_SERVICE_LAUNCHER
WSF_LIBFCGI_SERVICE_LAUNCHER [G]
create
make,
make_and_launch,
make_callback,
make_callback_and_launch
make_and_launch
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,24 +0,0 @@
note
description: "Summary description for {WSF_DEFAULT_RESPONSE_SERVICE}."
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_DEFAULT_RESPONSE_SERVICE
inherit
WSF_DEFAULT_SERVICE
WSF_RESPONSE_SERVICE
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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,13 +4,13 @@ note
revision: "$Revision$"
deferred class
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [G -> WSF_EXECUTION create make end]
inherit
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER]
WSF_DEFAULT_SERVICE_I [WSF_DEFAULT_SERVICE_LAUNCHER [G]]
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -6,19 +6,17 @@ note
revision: "$Revision$"
class
WSF_DEFAULT_SERVICE_LAUNCHER
WSF_DEFAULT_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
WSF_OPENSHIFT_SERVICE_LAUNCHER
WSF_OPENSHIFT_SERVICE_LAUNCHER [G]
create
make,
make_and_launch,
make_callback,
make_callback_and_launch
make_and_launch
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_httpd" uuid="5CBA8C5A-3191-434A-8DE1-C0C3CAC9C4F4" library_target="default_httpd">
<target name="default_httpd">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_standalone" uuid="5CBA8C5A-3191-434A-8DE1-C0C3CAC9C4F4" library_target="default_standalone">
<target name="default_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
@@ -11,7 +11,7 @@
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="wsf" location="..\wsf-safe.ecf"/>
<library name="wsf_httpd" location="..\connector\httpd-safe.ecf"/>
<cluster name="default_httpd" location=".\httpd\" recursive="true"/>
<library name="wsf_standalone" location="..\connector\standalone-safe.ecf"/>
<cluster name="default_standalone" location=".\standalone\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_standalone" uuid="5CBA8C5A-3191-434A-8DE1-C0C3CAC9C4F4" library_target="default_standalone">
<target name="default_standalone">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="provisional">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="wsf" location="..\wsf.ecf"/>
<library name="wsf_standalone" location="..\connector\standalone.ecf"/>
<cluster name="default_standalone" location=".\standalone\" recursive="true"/>
</target>
</system>

View File

@@ -1,6 +1,6 @@
note
description: "[
Default launcher for WSF_SERVICE based on {WSF_HTTPD_SERVICE_LAUNCHER}
Default launcher for WSF_SERVICE based on {WSF_STANDALONE_SERVICE_LAUNCHER}
]"
date: "$Date$"
revision: "$Revision$"
@@ -9,7 +9,7 @@ class
WSF_DEFAULT_SERVICE_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
WSF_HTTPD_SERVICE_LAUNCHER [G]
WSF_STANDALONE_SERVICE_LAUNCHER [G]
create
make,

View File

@@ -0,0 +1,92 @@
note
description: "Summary description for {WSF_FILTERED_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_FILTERED_EXECUTION
inherit
WSF_EXECUTION
redefine
initialize
end
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_filter
end
initialize_filter
-- Initialize `filter'
do
create_filter
setup_filter
end
create_filter
-- Create `filter'
deferred
ensure
filter_created: filter /= Void
end
setup_filter
-- Setup `filter'
require
filter_created: filter /= Void
deferred
end
append_filters (a_filters: ITERABLE [WSF_FILTER])
-- Append collection `a_filters' of filters to the end of the `filter' chain.
local
f: like filter
l_next_filter: detachable like filter
do
from
f := filter
l_next_filter := f.next
until
l_next_filter = Void
loop
f := l_next_filter
l_next_filter := f.next
end
check f_attached_without_next: f /= Void and then f.next = Void end
across
a_filters as ic
loop
l_next_filter := ic.item
f.set_next (l_next_filter)
f := l_next_filter
end
end
feature -- Access
filter: WSF_FILTER
-- Filter
feature -- Execution
execute
do
filter.execute (request, response)
end
;note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, 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

@@ -48,7 +48,7 @@ feature -- Execution
create l_sess
router.dispatch (req, res, l_sess)
if not l_sess.dispatched then
execute_default
execute_default (req, res)
end
end
end
@@ -279,7 +279,7 @@ invariant
unavailability_duration_xor_unavailable_until: unavailability_duration > 0 implies unavailable_until = Void
;note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,68 @@
note
description: "[
Execution which is first filtered, and then pass to the router
]"
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_FILTERED_ROUTED_EXECUTION
inherit
WSF_FILTERED_EXECUTION
redefine
initialize
end
WSF_ROUTED_EXECUTION
undefine
execute
redefine
initialize
end
WSF_FILTER
rename
execute as filter_execute
end
feature {NONE} -- Initialize
initialize
local
f: like filter
do
Precursor {WSF_ROUTED_EXECUTION}
Precursor {WSF_FILTERED_EXECUTION}
-- Current is a WSF_FILTER as well in order to call the router
-- let's add Current at the end of the filter chain.
from
f := filter
until
not attached f.next as l_next
loop
f := l_next
end
f.set_next (Current)
end
feature -- Execute Filter
filter_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter.
do
router_execute (req, res)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -7,6 +7,20 @@ note
deferred class
WSF_ROUTED_EXECUTION
inherit
WSF_EXECUTION
redefine
initialize
end
feature {NONE} -- Initialize
initialize
do
Precursor
initialize_router
end
feature -- Router
initialize_router
@@ -34,14 +48,6 @@ feature -- Router
feature -- Access
request: WSF_REQUEST
deferred
end
response: WSF_RESPONSE
deferred
end
router: WSF_ROUTER
-- Router used to dispatch the request according to the WSF_REQUEST object
-- and associated request methods
@@ -51,19 +57,22 @@ feature -- Execution
execute
-- Dispatch the request
-- and if handler is not found, execute the default procedure `execute_default'.
do
router_execute (request, response)
end
router_execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
sess: WSF_ROUTER_SESSION
do
create sess
router.dispatch (request, response, sess)
router.dispatch (req, res, sess)
if not sess.dispatched then
execute_default
execute_default (req, res)
end
ensure
response_status_is_set: response.status_is_set
end
execute_default
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Dispatch requests without a matching handler.
local
msg: WSF_DEFAULT_ROUTER_RESPONSE
@@ -73,4 +82,14 @@ feature -- Execution
response.send (msg)
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, 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

@@ -1,31 +1,22 @@
note
description: "[
Inherit from this class to implement the main entry of your web service
You just need to implement `execute', get data from the request `req'
and return a response message
]"
description: "Summary description for {WSF_EXECUTION_FACTORY}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
WSF_RESPONSE_SERVICE [G -> WSF_EXECUTION create make end]
WSF_EXECUTION_FACTORY
inherit
WSF_SERVICE
feature -- Response
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
deferred
ensure
Result_attached: Result /= Void
WGI_EXECUTION_FACTORY
redefine
execution
end
feature -- Execution
feature -- Factory
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
do
res.send (response (req))
execution (req: WGI_REQUEST; res: WGI_RESPONSE): WSF_EXECUTION
deferred
end
note

View File

@@ -19,7 +19,7 @@ note
class
WSF_RESPONSE
create {WSF_TO_WGI_SERVICE, WSF_EXECUTION, WGI_EXPORTER}
create {WSF_EXECUTION, WGI_EXPORTER}
make_from_wgi
create {WSF_RESPONSE}

View File

@@ -8,7 +8,7 @@ class
ECHO_SERVER
inherit
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [ECHO_SERVER_EXECUTION]
create
make
@@ -23,53 +23,4 @@ feature {NONE} -- Initialization
make_and_launch
end
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: WSF_PAGE_RESPONSE
l_body: STRING_8
do
create l_body.make (1024)
create page.make_with_body (l_body)
page.header.put_content_type_text_plain
l_body.append ("REQUEST_METHOD=" + req.request_method + "%N")
l_body.append ("REQUEST_URI=" + req.request_uri + "%N")
l_body.append ("PATH_INFO=" + req.path_info + "%N")
l_body.append ("QUERY_STRING=" + req.query_string + "%N")
l_body.append ("Query parameters:%N")
across
req.query_parameters as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
l_body.append ("Form parameters:%N")
across
req.form_parameters as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
l_body.append ("Meta variables:%N")
across
req.meta_variables as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
res.send (page)
end
feature -- Access
feature -- Change
feature {NONE} -- Implementation
invariant
-- invariant_clause: True
end

View File

@@ -0,0 +1,59 @@
note
description : "Objects that ..."
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
ECHO_SERVER_EXECUTION
inherit
WSF_EXECUTION
create
make
feature -- Execution
execute
local
req: WSF_REQUEST; res: WSF_RESPONSE
page: WSF_PAGE_RESPONSE
l_body: STRING_8
do
req := request
res := response
create l_body.make (1024)
create page.make_with_body (l_body)
page.header.put_content_type_text_plain
l_body.append ("REQUEST_METHOD=" + req.request_method + "%N")
l_body.append ("REQUEST_URI=" + req.request_uri + "%N")
l_body.append ("PATH_INFO=" + req.path_info + "%N")
l_body.append ("QUERY_STRING=" + req.query_string + "%N")
l_body.append ("Query parameters:%N")
across
req.query_parameters as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
l_body.append ("Form parameters:%N")
across
req.form_parameters as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
l_body.append ("Meta variables:%N")
across
req.meta_variables as q
loop
l_body.append ("%T"+ q.item.name + "=" + q.item.string_representation +"%N")
end
res.send (page)
end
end

View File

@@ -2,9 +2,9 @@ class
TEST
inherit
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [TEST_EXECUTION]
TEST_SERVICE
TEST_SERVICE [TEST_EXECUTION]
create
make
@@ -22,38 +22,6 @@ feature {NONE} -- Initialization
make_and_launch
end
feature -- Helper
server_log_path: STRING
local
fn: FILE_NAME
once
create fn.make_from_string ("server_test.log")
Result := fn.string
end
server_log (m: STRING_8)
local
f: RAW_FILE
do
create f.make (server_log_path)
f.open_append
f.put_string (m)
f.put_character ('%N')
f.close
end
base_url: detachable STRING
test_url (a_query_url: READABLE_STRING_8): READABLE_STRING_8
local
b: like base_url
do
b := base_url
if b = Void then
b := ""
end
Result := "/" + b + a_query_url
end
end

View File

@@ -0,0 +1,51 @@
note
description: "Summary description for {}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
TEST_EXECUTION
inherit
TEST_EXECUTION_I
create
make
feature -- Helper
server_log_path: STRING
local
fn: FILE_NAME
once
create fn.make_from_string ("server_test.log")
Result := fn.string
end
server_log (m: STRING_8)
local
f: RAW_FILE
do
create f.make (server_log_path)
f.open_append
f.put_string (m)
f.put_character ('%N')
f.close
end
base_url: detachable STRING
test_url (a_query_url: READABLE_STRING_8): READABLE_STRING_8
local
b: like base_url
do
b := base_url
if b = Void then
b := ""
end
Result := "/" + b + a_query_url
end
end

View File

@@ -0,0 +1,195 @@
note
description: "Summary description for {}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
TEST_EXECUTION_I
inherit
WSF_EXECUTION
feature -- Execution
execute
local
req: WSF_REQUEST
res: WSF_RESPONSE
q: detachable STRING_32
n: NATURAL_64
page: WSF_PAGE_RESPONSE
log_res: WSF_LOGGER_RESPONSE_WRAPPER
do
req := request
res := response
debug
server_log (req.request_uri)
if attached req.content_type as l_content_type then
server_log ("content_type:" + l_content_type.string)
end
end
if attached req.http_expect as l_expect and then l_expect.same_string ("100-continue") then
(create {EXECUTION_ENVIRONMENT}).sleep (900_000_000) -- 900 milliseconds
end
create page.make
if attached req.request_uri as l_uri then
if l_uri.starts_with (test_url ("get/01")) then
page.set_status_code (200)
page.header.put_content_type_text_plain
page.put_string ("get-01")
create q.make_empty
across
req.query_parameters as qcur
loop
if not q.is_empty then
q.append_character ('&')
end
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.string_representation)
end
if not q.is_empty then
page.put_string ("(" + q + ")")
end
elseif l_uri.starts_with (test_url ("post/01")) then
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("post-01")
create q.make_empty
across
req.query_parameters as qcur
loop
if not q.is_empty then
q.append_character ('&')
end
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.string_representation)
end
if not q.is_empty then
page.put_string ("(" + q + ")")
end
create q.make_empty
-- req.set_raw_input_data_recorded (True)
across
req.form_parameters as fcur
loop
debug
server_log ("%Tform: " + fcur.item.name)
end
if not q.is_empty then
q.append_character ('&')
end
q.append (fcur.item.name.as_string_32 + "=" + fcur.item.string_representation)
end
-- if attached req.raw_input_data as d then
-- server_log ("Raw data=" + d)
-- end
if not q.is_empty then
page.put_string (" : " + q )
end
elseif l_uri.starts_with (test_url ("post/file/01")) then
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("post-file-01")
n := req.content_length_value
if n > 0 then
req.input.read_string (n.to_integer_32)
q := req.input.last_string
page.put_string ("%N" + q)
end
else
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("Hello")
end
else
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("Bye")
end
if
attached new_file (req, "output.log") as l_out and
attached new_file (req, "error.log") as l_err
then
create log_res.make_from_response (res, l_out, l_err)
log_res.send (page)
l_out.close
l_err.close
else
check False end
res.send (page)
end
end
new_file (req: WSF_REQUEST; a_suffix: STRING): detachable FILE
local
dp, p, fp: FILE_NAME
d: DIRECTORY
i: INTEGER
f: detachable FILE
retried: INTEGER
do
if retried = 0 then
create dp.make_from_string ("logs")
create d.make (dp.string)
if not d.exists then
d.recursive_create_dir
end
if attached req.request_time_stamp as t then
create p.make_from_string (t.out)
else
create p.make_from_string ("")
end
from
i := 0
create fp.make_from_string (dp.string)
if p.is_empty then
fp.set_file_name (p.string + a_suffix)
else
fp.set_file_name (p.string + "-" + a_suffix)
end
create {PLAIN_TEXT_FILE} f.make (fp.string)
until
not f.exists
loop
i := i + 1
create fp.make_from_string (dp.string)
if p.is_empty then
fp.set_file_name (p.string + i.out + "-" + a_suffix)
else
fp.set_file_name (p.string + "_" + i.out + "-" + a_suffix)
end
f.make (fp.string)
end
f.open_write
elseif retried < 5 then
-- Eventually another request created the file at the same time ..
f := new_file (req, a_suffix)
else
f := Void
end
Result := f
rescue
retried := retried + 1
retry
end
feature -- Helper
server_log (s: STRING)
deferred
end
test_url (a_query_url: READABLE_STRING_8): READABLE_STRING_8
deferred
end
end

View File

@@ -5,187 +5,11 @@ note
revision: "$Revision$"
deferred class
TEST_SERVICE
TEST_SERVICE [G -> TEST_EXECUTION_I create make end]
inherit
WSF_SERVICE
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
q: detachable STRING_32
n: NATURAL_64
page: WSF_PAGE_RESPONSE
log_res: WSF_LOGGER_RESPONSE_WRAPPER
do
debug
server_log (req.request_uri)
if attached req.content_type as l_content_type then
server_log ("content_type:" + l_content_type.string)
end
end
if attached req.http_expect as l_expect and then l_expect.same_string ("100-continue") then
(create {EXECUTION_ENVIRONMENT}).sleep (900_000_000) -- 900 milliseconds
end
create page.make
if attached req.request_uri as l_uri then
if l_uri.starts_with (test_url ("get/01")) then
page.set_status_code (200)
page.header.put_content_type_text_plain
page.put_string ("get-01")
create q.make_empty
across
req.query_parameters as qcur
loop
if not q.is_empty then
q.append_character ('&')
end
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.string_representation)
end
if not q.is_empty then
page.put_string ("(" + q + ")")
end
elseif l_uri.starts_with (test_url ("post/01")) then
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("post-01")
create q.make_empty
across
req.query_parameters as qcur
loop
if not q.is_empty then
q.append_character ('&')
end
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.string_representation)
end
if not q.is_empty then
page.put_string ("(" + q + ")")
end
create q.make_empty
-- req.set_raw_input_data_recorded (True)
across
req.form_parameters as fcur
loop
debug
server_log ("%Tform: " + fcur.item.name)
end
if not q.is_empty then
q.append_character ('&')
end
q.append (fcur.item.name.as_string_32 + "=" + fcur.item.string_representation)
end
-- if attached req.raw_input_data as d then
-- server_log ("Raw data=" + d)
-- end
if not q.is_empty then
page.put_string (" : " + q )
end
elseif l_uri.starts_with (test_url ("post/file/01")) then
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("post-file-01")
n := req.content_length_value
if n > 0 then
req.input.read_string (n.to_integer_32)
q := req.input.last_string
page.put_string ("%N" + q)
end
else
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("Hello")
end
else
page.put_header (200, <<["Content-Type", "text/plain"]>>)
page.put_string ("Bye")
end
if
attached new_file (req, "output.log") as l_out and
attached new_file (req, "error.log") as l_err
then
create log_res.make_from_response (res, l_out, l_err)
log_res.send (page)
l_out.close
l_err.close
else
check False end
res.send (page)
end
end
new_file (req: WSF_REQUEST; a_suffix: STRING): detachable FILE
local
dp, p, fp: FILE_NAME
d: DIRECTORY
i: INTEGER
f: detachable FILE
retried: INTEGER
do
if retried = 0 then
create dp.make_from_string ("logs")
create d.make (dp.string)
if not d.exists then
d.recursive_create_dir
end
if attached req.request_time_stamp as t then
create p.make_from_string (t.out)
else
create p.make_from_string ("")
end
from
i := 0
create fp.make_from_string (dp.string)
if p.is_empty then
fp.set_file_name (p.string + a_suffix)
else
fp.set_file_name (p.string + "-" + a_suffix)
end
create {PLAIN_TEXT_FILE} f.make (fp.string)
until
not f.exists
loop
i := i + 1
create fp.make_from_string (dp.string)
if p.is_empty then
fp.set_file_name (p.string + i.out + "-" + a_suffix)
else
fp.set_file_name (p.string + "_" + i.out + "-" + a_suffix)
end
f.make (fp.string)
end
f.open_write
elseif retried < 5 then
-- Eventually another request created the file at the same time ..
f := new_file (req, a_suffix)
else
f := Void
end
Result := f
rescue
retried := retried + 1
retry
end
feature -- Helper
server_log (s: STRING)
deferred
end
test_url (a_query_url: READABLE_STRING_8): READABLE_STRING_8
deferred
end
end

View File

@@ -17,14 +17,9 @@ inherit
on_clean
end
TEST_SERVICE
undefine
default_create
end
feature {NONE} -- Events
web_app: detachable NINO_SERVICE
web_app: detachable NINO_SERVICE [TEST_EXECUTION]
port_number: INTEGER
base_url: detachable STRING
@@ -32,7 +27,7 @@ feature {NONE} -- Events
on_prepare
-- <Precursor>
local
app: NINO_SERVICE
app: NINO_SERVICE [TEST_EXECUTION]
wt: WORKER_THREAD
e: EXECUTION_ENVIRONMENT
do
@@ -43,7 +38,7 @@ feature {NONE} -- Events
port_number := 0
base_url := "/test/"
create app.make_custom (to_wgi_service, base_url)
create app.make_custom (base_url)
web_app := app
create wt.make (agent app.listen (port_number))

View File

@@ -7,15 +7,13 @@ class
TEST_WSF_RESPONSE_TEST_SUITE
inherit
WSF_TO_WGI_SERVICE
rename
default_create as df_wgi,
execute as execute_wgi
end
EQA_TEST_SET
redefine
on_prepare
select
end
WGI_EXPORTER
undefine
default_create
end
@@ -23,7 +21,6 @@ feature {NONE} -- Events
on_prepare
do
make_from_service (create {WSF_SERVICE_NULL})
end
feature -- Test Cases
@@ -96,7 +93,7 @@ feature -- Test Cases
end
test_add_multiple_cookie_with_similar_cookie_name_2
test_add_multiple_cookie_with_similar_cookie_name_2
local
w_res: WSF_RESPONSE
l_cookie: WSF_COOKIE

View File

@@ -1,26 +0,0 @@
note
description: "[
Mock implementation of the WGI_SERVICE interface.
Used for testing the ewf core and also web applications
]"
date: "$Date$"
revision: "$Revision$"
class
WSF_SERVICE_NULL
inherit
WSF_SERVICE
feature -- Execute
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
do
end
end