Migrated most of the example and library to new design.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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]
|
||||
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -12,7 +12,7 @@ inherit
|
||||
|
||||
feature -- Access
|
||||
|
||||
connector: detachable separate WGI_HTTPD_CONNECTOR [G]
|
||||
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
|
||||
|
||||
feature -- Element change
|
||||
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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>
|
||||
23
library/server/ewsgi/connectors/standalone/standalone.ecf
Normal file
23
library/server/ewsgi/connectors/standalone/standalone.ecf
Normal 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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
22
library/server/wsf/connector/standalone.ecf
Normal file
22
library/server/wsf/connector/standalone.ecf
Normal 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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
17
library/server/wsf/default/standalone.ecf
Normal file
17
library/server/wsf/default/standalone.ecf
Normal 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>
|
||||
@@ -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,
|
||||
92
library/server/wsf/router/filter/wsf_filtered_execution.e
Normal file
92
library/server/wsf/router/filter/wsf_filtered_execution.e
Normal 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
|
||||
@@ -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
|
||||
|
||||
68
library/server/wsf/router/wsf_filtered_routed_execution.e
Normal file
68
library/server/wsf/router/wsf_filtered_routed_execution.e
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
59
library/server/wsf/tests/echo/src/echo_server_execution.e
Normal file
59
library/server/wsf/tests/echo/src/echo_server_execution.e
Normal 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
|
||||
@@ -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
|
||||
|
||||
51
library/server/wsf/tests/server/test_execution.e
Normal file
51
library/server/wsf/tests/server/test_execution.e
Normal 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
|
||||
|
||||
195
library/server/wsf/tests/server/test_execution_i.e
Normal file
195
library/server/wsf/tests/server/test_execution_i.e
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user