Added readme files to the examples.

Minor changes in various ecf file and code.
Moved filter example under _update_needed since it has obsolete code.
This commit is contained in:
2017-02-14 11:21:32 +01:00
parent fbdf034b9b
commit b93cb17f7c
26 changed files with 139 additions and 46 deletions

View File

@@ -0,0 +1,14 @@
Examples to update
==================
This folder contains a few examples that needs to be updated.
It could be for many reason
- using obsolete components
- bad style
- not using latest EiffelWeb features
- issue in SCOOP concurrency mode
- ...
## filter
It demonstrates how to use the `WSF_FILTER` components. It can be used for authentication, and various usage (logging, setting specific http header such as CORS related settings, ...).

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E">
<target name="common">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option debug="true" warning="true" void_safety="all">
<assertions precondition="true" postcondition="true" invariant="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
<library name="http" location="..\..\..\library\network\protocol\http\http-safe.ecf" readonly="true"/>
<library name="http_authorization" location="..\..\..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="true"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="true"/>
<library name="wsf" location="..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_extension" location="..\..\..\library\server\wsf\wsf_extension-safe.ecf" readonly="true"/>
<library name="wsf_router_context" location="..\..\..\library\server\wsf\wsf_router_context-safe.ecf" readonly="true"/>
</target>
<target name="filter_standalone" extends="common">
<root class="FILTER_SERVER" feature="make"/>
<setting name="concurrency" value="thread"/>
<library name="default_standalone" location="..\..\..\library\server\wsf\default\standalone-safe.ecf" readonly="true"/>
<cluster name="filter" location="src\" recursive="true"/>
</target>
<target name="filter_fcgi" extends="common">
<root class="FILTER_SERVER" feature="make"/>
<library name="default_libfcgi" location="..\..\..\library\server\wsf\default\libfcgi-safe.ecf"/>
<cluster name="filter" location="src\" recursive="true"/>
</target>
<target name="filter" extends="filter_standalone">
</target>
</system>

View File

@@ -0,0 +1,4 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -0,0 +1,4 @@
Filter example
To test the example, you can just run in a terminal:
> curl -u foo:bar http://localhost:9090/user/1 -v

View File

@@ -0,0 +1,64 @@
note
description: "Summary description for {DATABASE_API}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
DATABASE_API
create
make
feature -- Initialization
make
local
l_user: USER
do
create users.make (10)
create l_user.make (1, "foo", "bar")
users.put (l_user, l_user.id)
create l_user.make (2, "demo", "demo")
users.put (l_user, l_user.id)
end
feature -- Access
user_by_id (a_id: INTEGER): detachable USER
do
Result := users.item (a_id)
end
user_by_name (a_name: READABLE_STRING_GENERAL): detachable USER
do
across
users as c
until
Result /= Void
loop
if attached c.item as u and then a_name.same_string (u.name) then
Result := u
end
end
end
user (a_id: INTEGER; a_name: detachable READABLE_STRING_GENERAL): detachable USER
-- User with id `a_id' or name `a_name'.
require
a_id > 0 xor a_name /= Void
do
if a_id > 0 then
Result := user_by_id (a_id)
elseif a_name /= Void then
Result := user_by_name (a_name)
end
ensure
Result /= Void implies ((a_id > 0 and then Result.id = a_id) xor (a_name /= Void and then Result.name.same_string_general (a_name)))
end
users: HASH_TABLE [USER, INTEGER]
;note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,20 @@
note
description: "Summary description for {SHARED_DATABASE_API}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SHARED_DATABASE_API
feature -- Access
db_access: DATABASE_API
once
create Result.make
end
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,52 @@
note
description: "JSON user converter."
author: "Olivier Ligot"
date: "$Date$"
revision: "$Revision$"
class
JSON_USER_CONVERTER
inherit
JSON_CONVERTER
create
make
feature {NONE} -- Initialization
make
do
create object.make (0, "", "")
end
feature -- Access
object: USER
value: detachable JSON_OBJECT
feature -- Conversion
from_json (j: attached like value): detachable like object
-- Convert from JSON value.
do
end
to_json (o: like object): like value
-- Convert to JSON value.
do
create Result.make
Result.put (json.value (o.id), id_key)
Result.put (json.value (o.name), name_key)
end
feature {NONE} -- Implementation
id_key: STRING = "id"
name_key: STRING = "name"
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,59 @@
note
description: "User."
author: ""
date: "$Date$"
revision: "$Revision$"
class
USER
inherit
ANY
redefine
is_equal
end
create
make
feature {NONE} -- Initialization
make (an_id: INTEGER; a_name, a_password: STRING)
do
id := an_id
name := a_name
password := a_password
ensure
id_set: id = an_id
name_set: name = a_name
password_set: password = a_password
end
feature -- Access
id: INTEGER
-- Identifier
name: STRING
-- Name
password: STRING
-- Password
feature -- Comparison
is_equal (other: like Current): BOOLEAN
-- Is `other' attached to an object considered
-- equal to current object?
do
if Current = other then
Result := True
else
Result := (id = other.id) and (name = other.name) and (password = other.password)
end
end
;note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,78 @@
note
description: "Authentication filter."
author: "Olivier Ligot"
date: "$Date$"
revision: "$Revision$"
class
AUTHENTICATION_FILTER
inherit
WSF_FILTER
WSF_URI_TEMPLATE_HANDLER
SHARED_DATABASE_API
SHARED_EJSON
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter
local
l_auth: detachable HTTP_AUTHORIZATION
do
if attached req.http_authorization as l_http_authorization then
create l_auth.make (l_http_authorization)
end
if
l_auth /= Void and then
l_auth.is_basic and then
attached l_auth.login as l_auth_login and then
attached Db_access.user (0, l_auth_login) as l_user and then
l_auth_login.same_string (l_user.name) and then
attached l_auth.password as l_auth_password and then
l_auth_password.same_string (l_user.password)
then
req.set_execution_variable ("user", l_user)
execute_next (req, res)
else
handle_unauthorized ("Unauthorized", req, res)
end
end
feature {NONE} -- Implementation
handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle forbidden.
local
h: HTTP_HEADER
s: STRING
do
create h.make
h.put_content_type_text_plain
h.put_content_length (a_description.count)
h.put_current_date
s := "Basic realm=%"For this demo, use any of: "
across
db_access.users as ic
loop
s.append_character ('(')
s.append (ic.item.name)
s.append_character (':')
s.append (ic.item.password)
s.append_character (')')
s.append_character (' ')
end
s.append_character ('"')
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, s)
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
res.put_string (a_description)
end
note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,34 @@
note
description: "Summary description for {FILTER_HANDLER_CONTEXT}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
FILTER_HANDLER_CONTEXT
inherit
WSF_HANDLER_CONTEXT
create
make
feature -- Access
user: detachable USER
-- Authenticated user
feature -- Element change
set_user (a_user: USER)
-- Set `user' to `a_user'
do
user := a_user
ensure
user_set: user = a_user
end
note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,50 @@
note
description : "Filter example."
author : "Olivier Ligot"
date : "$Date$"
revision : "$Revision$"
class
FILTER_SERVER
inherit
WSF_DEFAULT_SERVICE [FILTER_SERVER_EXECUTION]
create
make
feature {NONE} -- Initialization
make
local
l_message: STRING
l_factory: INET_ADDRESS_FACTORY
do
set_service_option ("port", port)
create l_message.make_empty
l_message.append_string ("Launching filter server at ")
create l_factory
l_message.append_string (l_factory.create_localhost.host_name)
l_message.append_string (" port ")
l_message.append_integer (port)
io.put_string (l_message)
io.put_new_line
make_and_launch
end
feature {NONE} -- Implementation
port: INTEGER = 9090
-- Port number
note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,82 @@
note
description : "Filter example."
author : "Olivier Ligot"
date : "$Date$"
revision : "$Revision$"
class
FILTER_SERVER_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
redefine
initialize
end
SHARED_EJSON
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_json
end
create_filter
-- Create `filter'
do
create {WSF_CORS_FILTER} filter
end
setup_filter
-- Setup `filter'
local
l_logging_filter: WSF_LOGGING_FILTER
do
create l_logging_filter
filter.set_next (l_logging_filter)
end
setup_router
-- Setup `router'
local
l_options_filter: WSF_CORS_OPTIONS_FILTER
l_authentication_filter: AUTHENTICATION_FILTER
l_user_filter: USER_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_options_filter.make (router)
create l_authentication_filter
create l_user_filter
l_options_filter.set_next (l_authentication_filter)
l_authentication_filter.set_next (l_user_filter)
create l_methods
l_methods.enable_options
l_methods.enable_get
router.handle ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
end
initialize_json
-- Initialize `json'.
once
-- See SHARED_EJSON, and the once function per thread `json'.
json.add_converter (create {JSON_USER_CONVERTER}.make)
end
note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,99 @@
note
description: "User handler."
author: "Olivier Ligot"
date: "$Date$"
revision: "$Revision$"
class
USER_HANDLER
inherit
WSF_FILTER
WSF_URI_TEMPLATE_HANDLER
WSF_RESOURCE_HANDLER_HELPER
redefine
do_get
end
SHARED_DATABASE_API
SHARED_EJSON
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (req, res)
execute_next (req, res)
end
do_get (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Using GET to retrieve resource information.
-- If the GET request is SUCCESS, we response with
-- 200 OK, and a representation of the user
-- If the GET request is not SUCCESS, we response with
-- 404 Resource not found
require else
authenticated_user_attached: attached {USER} req.execution_variable ("user")
local
id : STRING
do
if attached req.path_info as orig_path then
id := get_user_id_from_path (orig_path)
if attached retrieve_user (id) as l_user then
if l_user ~ req.execution_variable ("user") then
compute_response_get (req, res, l_user)
elseif attached {USER} req.execution_variable ("user") as l_auth_user then
-- Trying to access another user that the authenticated one,
-- which is forbidden in this example...
handle_forbidden ("You try to access the user " + id.out + " while authenticating with the user " + l_auth_user.id.out, req, res)
end
else
handle_resource_not_found_response ("The following resource " + orig_path + " is not found ", req, res)
end
end
end
feature {NONE} -- Implementation
compute_response_get (req: WSF_REQUEST; res: WSF_RESPONSE; l_user : USER)
local
h: HTTP_HEADER
l_msg : STRING
do
create h.make
h.put_content_type_application_json
if attached {JSON_VALUE} json.value (l_user) as jv then
l_msg := jv.representation
h.put_content_length (l_msg.count)
if attached req.request_time as time then
h.put_utc_date (time)
end
res.set_status_code ({HTTP_STATUS_CODE}.ok)
res.put_header_text (h.string)
res.put_string (l_msg)
end
end
get_user_id_from_path (a_path: READABLE_STRING_32): STRING
do
Result := a_path.split ('/').at (3)
end
retrieve_user (id: STRING) : detachable USER
-- Retrieve the user by id if it exist, in other case, Void
do
if id.is_integer then
Result := db_access.user_by_id (id.to_integer)
else
Result := db_access.user_by_name (id)
end
end
note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end