Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fffa763d05 | |||
| d015c065f6 | |||
| 8ea443c115 | |||
| 019393fdb1 | |||
| da8028f8b3 | |||
| 20ed000879 | |||
|
|
24620b228c | ||
|
|
9c7e29b836 | ||
|
|
a0e9a41e21 | ||
|
|
dd9aff03d3 | ||
|
|
dc35925eb0 | ||
| a1a620a9c3 | |||
| d8ea9ba63c | |||
| c42af5b2de | |||
| d9cbc72058 | |||
| 7e057b20b1 | |||
| 3165c1e5c6 | |||
| 89e26519e4 | |||
| 9d20e85c03 | |||
| 48cb99498c | |||
| 8246bc1444 | |||
| 9e1083eba8 | |||
| 4907bc3085 | |||
| 7d2ce8a77f | |||
| b4a9c92ffc | |||
| bf0eb9a02d | |||
| ddf73077b3 | |||
| 3da80fce0d | |||
| 0970de5dc6 | |||
| 557b11f4e6 | |||
| 7f27a6c797 |
121
MIGRATION.md
Normal file
121
MIGRATION.md
Normal file
@@ -0,0 +1,121 @@
|
||||
Date: 2015-mar-31
|
||||
|
||||
# Goal:
|
||||
=======
|
||||
- support safe concurrency with EWF
|
||||
- provide a concurrent standalone connector
|
||||
|
||||
# Status:
|
||||
=========
|
||||
- The current version of EWF has mainly 3 connectors: CGI, libFCGI, and nino.
|
||||
- CGI and libFCGI connectors does not need any concurrency support.
|
||||
- But the nino connector had a pseudo concurrency support with Thread, however one could do write code that result in hasardeous concurrency execution.
|
||||
|
||||
So, it was decided to provide an improved Eiffel web nino connector, and update EWF design to make it concurrency compliant.
|
||||
|
||||
# Decisions:
|
||||
============
|
||||
- instead of updating current nino library, we now have a new "standalone" connector which is inspired by nino, but have support for the 3 concurrency modes: none, thread and SCOOP.
|
||||
|
||||
|
||||
# Overview
|
||||
==========
|
||||
Adding support for SCOOP concurrency mode add constraints to the design, but also helps ensuring the concurrency design of EWF is correct.
|
||||
|
||||
As a consequence, we had to introduce a new interface WSF_EXECUTION which is instantiated for each incoming request. See its simplified interface :
|
||||
<code lang="eiffel">
|
||||
deferred class WSF_EXECUTION
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (req: WGI_REQUEST; res: WGI_RESPONSE)
|
||||
do
|
||||
...
|
||||
īnitialize
|
||||
end
|
||||
|
||||
initialize
|
||||
-- Initialize Current object.
|
||||
--| To be redefined if needed.
|
||||
do
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
request: WSF_REQUEST
|
||||
-- Access to request data.
|
||||
-- Header, Query, Post, Input data..
|
||||
|
||||
response: WSF_RESPONSE
|
||||
-- Access to output stream, back to the client.
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute
|
||||
-- Execute Current `request',
|
||||
-- getting data from `request'
|
||||
-- and response to client via `response'.
|
||||
deferred
|
||||
ensure
|
||||
is_valid_end_of_execution: is_valid_end_of_execution
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
And the related request execution routines are extracted from WSF_SERVICE which becomes almost useless. The "service" part is not mostly responsible of launching the expected connector and set optional options, and declare the type of "execution" interface.
|
||||
|
||||
As a result, the well known WSF_DEFAULT_SERVICE has now a formal generic that should conform to WSF_EXECUTION with a `make' creation procedure. See update code:
|
||||
|
||||
<code lang="eiffel">
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
-- Initialize current service.
|
||||
do
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
Where APPLICATION_EXECUTION is an implementation of the WSF_EXECUTION interface (with the `make' creation procedure).
|
||||
|
||||
In addition to add better and safer concurrency support, there are other advantages:
|
||||
- we now have a clear separation between the service launcher, and the request execution itself.
|
||||
- the WSF_EXECUTION is created per request, with two main attributes <code>request: WSF_REQUEST</code> and <code>response: WSF_RESPONSE</code>.
|
||||
|
||||
# How to migrate to new design
|
||||
- you can check the various example from the EWF repository, there should all be migrated to new design and comparing previous and new code, this will show you how the migration was done.
|
||||
- a frequent process:
|
||||
- identify the root class of your service, (the class implementing the WSF_SERVICE), let us name it APPLICATION_SERVICE
|
||||
- copy the APPLICATION_SERVICE file to APPLICATION_EXECUTION file.
|
||||
- change the class name to be APPLICATION_EXECUTION, and replace _SERVICE occurences by _EXECUTION (note the new WSF_ROUTED_EXECUTION and so on, which are mainly migration from previous WSF_ROUTED_SERVICE .., and also WSF_FILTERED_ROUTED_EXECUTION which is new.
|
||||
- replace "make_and_launch" by "make", remove the initialize redefinition if any.
|
||||
- in the APPLICATION_SERVICE class, remove most of the ROUTED, FILTERED ... inheritance, and keep WSF_DEFAULT_SERVICE, with a new formal generic i.e WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION].
|
||||
- in the eventual redefined initialize, remove code related to routers, filters, ...
|
||||
- remove all the execution related code.
|
||||
- And you should be done.
|
||||
- To be short, this is mostly creating a new _EXECUTION class, and move the execution related code into this class from the _SERVICE class.
|
||||
- Then, you can replace the usage of nino connector by using the new "Standalone" connector, and switch to SCOOP concurrency mode, to ensure you are not messing up with concurrency. Your own code/libraris may not be SCOOP compliant, we recommend to migrate to SCOOP, but as an intermediate solutioņ, you can use the other concurrency mode (none or thread).
|
||||
|
||||
Note: the new design impacts the _SERVICE classes, connectors, but WSF_REQUEST, WSF_RESPONSE , WSF_ROUTER are compatible, so the migration is really easy.
|
||||
|
||||
We may take the opportunity to update the design deeper according to user feedback, and eventually "wsf" library will be renamed "wsf2".
|
||||
This is work in progress, all comments , feedback, suggestions, bug report are welcome.
|
||||
Hopefully before the final version of the new design is out.
|
||||
|
||||
|
||||
@@ -8,23 +8,11 @@ class
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SERVICE
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
WSF_FILTERED_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
WSF_FILTER
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
@@ -33,75 +21,8 @@ feature {NONE} -- Initialization
|
||||
initialize
|
||||
-- Initialize current service.
|
||||
do
|
||||
initialize_router
|
||||
initialize_filter
|
||||
Precursor
|
||||
set_service_option ("port", 7070)
|
||||
end
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
local
|
||||
f, l_filter: detachable WSF_FILTER
|
||||
do
|
||||
l_filter := Void
|
||||
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
|
||||
-- Logging
|
||||
create {WSF_LOGGING_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
filter := l_filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
local
|
||||
f: WSF_FILTER
|
||||
do
|
||||
from
|
||||
f := filter
|
||||
until
|
||||
not attached f.next as l_next
|
||||
loop
|
||||
f := l_next
|
||||
end
|
||||
f.set_next (Current)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: EMPTY_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
note
|
||||
description: "simple application root class"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_FILTERED_ROUTED_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
do
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
do
|
||||
append_filters (<<create {WSF_LOGGING_FILTER}>>)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: EMPTY_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -8,23 +8,11 @@ class
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SERVICE
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
WSF_FILTERED_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
WSF_FILTER
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
@@ -33,75 +21,8 @@ feature {NONE} -- Initialization
|
||||
initialize
|
||||
-- Initialize current service.
|
||||
do
|
||||
initialize_router
|
||||
initialize_filter
|
||||
Precursor
|
||||
set_service_option ("port", 7070)
|
||||
end
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
local
|
||||
f, l_filter: detachable WSF_FILTER
|
||||
do
|
||||
l_filter := Void
|
||||
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
|
||||
-- Logging
|
||||
create {WSF_LOGGING_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
filter := l_filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
local
|
||||
f: WSF_FILTER
|
||||
do
|
||||
from
|
||||
f := filter
|
||||
until
|
||||
not attached f.next as l_next
|
||||
loop
|
||||
f := l_next
|
||||
end
|
||||
f.set_next (Current)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: EMPTY_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
note
|
||||
description: "simple application root class"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_FILTERED_ROUTED_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
do
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
do
|
||||
append_filters (<< create {WSF_LOGGING_FILTER} >>)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: EMPTY_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -8,168 +8,22 @@ class
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SERVICE
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
WSF_FILTERED_SERVICE
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
WSF_FILTER
|
||||
rename
|
||||
execute as execute_router
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
-- tt
|
||||
-- local
|
||||
-- lst: ARRAYED_LIST [READABLE_STRING_GENERAL]
|
||||
-- do
|
||||
-- create lst.make (3)
|
||||
-- lst.compare_objects
|
||||
-- lst.extend ({STRING_32} "abc")
|
||||
-- if lst.has ("abc") then
|
||||
-- print ("found%N")
|
||||
-- end
|
||||
-- end
|
||||
|
||||
initialize
|
||||
-- Initialize current service.
|
||||
do
|
||||
-- tt
|
||||
initialize_router
|
||||
initialize_filter
|
||||
Precursor
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
local
|
||||
f, l_filter: detachable WSF_FILTER
|
||||
do
|
||||
l_filter := Void
|
||||
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
|
||||
-- Logging
|
||||
create {WSF_LOGGING_FILTER} f
|
||||
f.set_next (l_filter)
|
||||
l_filter := f
|
||||
filter := l_filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
local
|
||||
f: WSF_FILTER
|
||||
do
|
||||
from
|
||||
f := filter
|
||||
until
|
||||
not attached f.next as l_next
|
||||
loop
|
||||
f := l_next
|
||||
end
|
||||
f.set_next (Current)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
map_agent_uri ("/grid", agent grid_demo, Void)
|
||||
map_agent_uri ("/repeater", agent repeater_demo, Void)
|
||||
map_agent_uri ("/slider", agent slider_demo, Void)
|
||||
map_agent_uri ("/upload", agent upload_demo, Void)
|
||||
map_agent_uri ("/codeview", agent codeview, Void)
|
||||
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: SAMPLE_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
grid_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: GRID_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
repeater_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: REPEATER_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
slider_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: SLIDER_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
upload_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: UPLOAD_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
codeview (request: WSF_REQUEST; response: WSF_RESPONSE)
|
||||
local
|
||||
page: CODEVIEW_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (request, response)
|
||||
page.execute
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
note
|
||||
description: "Summary description for {APPLICATION_EXECUTION}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_FILTERED_ROUTED_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Router and Filter
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
do
|
||||
-- Maintenance
|
||||
create {WSF_MAINTENANCE_FILTER} filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
do
|
||||
append_filters (<<create {WSF_LOGGING_FILTER}>>)
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
map_agent_uri ("/grid", agent grid_demo, Void)
|
||||
map_agent_uri ("/repeater", agent repeater_demo, Void)
|
||||
map_agent_uri ("/slider", agent slider_demo, Void)
|
||||
map_agent_uri ("/upload", agent upload_demo, Void)
|
||||
map_agent_uri ("/codeview", agent codeview, Void)
|
||||
|
||||
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
|
||||
-- this way, it handles the caching and so on
|
||||
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
|
||||
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
|
||||
do
|
||||
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: SAMPLE_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
grid_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: GRID_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
repeater_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: REPEATER_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
slider_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: SLIDER_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
upload_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: UPLOAD_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
codeview (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
page: CODEVIEW_PAGE
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
create page.make (req, res)
|
||||
page.execute
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {CONTACT_AUTOCOMPLETION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {FLAG_AUTOCOMPLETION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GOOGLE_AUTOCOMPLETION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {BASE_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {CODEVIEW_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GOOGLE_NEWS}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GOOGLE_NEWS_DATASOURCE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GOOGLE_NEWS_REPEATER}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {GRID_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {OWN_VALIDATOR}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {INCREASING_PROGRESSSOURCE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {REPEATER_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {SAMPLE_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {SLIDER_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {UPLOAD_PAGE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -18,12 +18,20 @@
|
||||
</target>
|
||||
<target name="debug_any" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="cgi" location="..\..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf"/>
|
||||
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
|
||||
<library name="standalone" location="..\..\library\server\wsf\connector\standalone-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="debug_standalone" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
|
||||
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="debug_nino" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
@@ -32,7 +40,7 @@
|
||||
</target>
|
||||
<target name="debug_cgi" extends="common">
|
||||
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
|
||||
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
|
||||
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/>
|
||||
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -8,10 +8,10 @@ note
|
||||
revision: "$Revision: 36 $"
|
||||
|
||||
class
|
||||
APPLICATION_LAUNCHER
|
||||
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
APPLICATION_LAUNCHER_I
|
||||
APPLICATION_LAUNCHER_I [G]
|
||||
|
||||
feature -- Custom
|
||||
|
||||
|
||||
@@ -10,24 +10,26 @@ note
|
||||
revision: "$Revision: 36 $"
|
||||
|
||||
deferred class
|
||||
APPLICATION_LAUNCHER_I
|
||||
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
feature -- Execution
|
||||
|
||||
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
nature: like launcher_nature
|
||||
do
|
||||
nature := launcher_nature
|
||||
if nature = Void or else nature = nature_nino then
|
||||
launch_nino (a_service, opts)
|
||||
if nature = Void or else nature = nature_standalone then
|
||||
launch_standalone (opts)
|
||||
elseif nature = nature_nino then
|
||||
launch_nino (opts)
|
||||
elseif nature = nature_cgi then
|
||||
launch_cgi (a_service, opts)
|
||||
launch_cgi (opts)
|
||||
elseif nature = nature_libfcgi then
|
||||
launch_libfcgi (a_service, opts)
|
||||
launch_libfcgi (opts)
|
||||
else
|
||||
-- bye bye
|
||||
(create {EXCEPTIONS}).die (-1)
|
||||
@@ -43,14 +45,16 @@ feature {NONE} -- Access
|
||||
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
|
||||
local
|
||||
p: PATH
|
||||
l_entry_name: READABLE_STRING_32
|
||||
ext: detachable READABLE_STRING_32
|
||||
do
|
||||
create p.make_from_string (execution_environment.arguments.command_name)
|
||||
if attached p.entry as l_entry then
|
||||
ext := l_entry.extension
|
||||
ext := l_entry.extension
|
||||
end
|
||||
if ext /= Void then
|
||||
if ext.same_string (nature_standalone) then
|
||||
Result := nature_standalone
|
||||
end
|
||||
if ext.same_string (nature_nino) then
|
||||
Result := nature_nino
|
||||
end
|
||||
@@ -61,39 +65,51 @@ feature {NONE} -- Access
|
||||
Result := nature_libfcgi
|
||||
end
|
||||
end
|
||||
Result := nature_standalone
|
||||
end
|
||||
|
||||
feature {NONE} -- nino
|
||||
|
||||
nature_standalone: STRING = "standalone"
|
||||
|
||||
launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
|
||||
do
|
||||
create launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
feature {NONE} -- nino
|
||||
|
||||
nature_nino: STRING = "nino"
|
||||
|
||||
launch_nino (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
launch_nino (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_NINO_SERVICE_LAUNCHER
|
||||
launcher: WSF_NINO_SERVICE_LAUNCHER [G]
|
||||
do
|
||||
create launcher.make_and_launch (a_service, opts)
|
||||
create launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
feature {NONE} -- cgi
|
||||
|
||||
nature_cgi: STRING = "cgi"
|
||||
|
||||
launch_cgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_CGI_SERVICE_LAUNCHER
|
||||
launcher: WSF_CGI_SERVICE_LAUNCHER [G]
|
||||
do
|
||||
create launcher.make_and_launch (a_service, opts)
|
||||
create launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
feature {NONE} -- libfcgi
|
||||
|
||||
nature_libfcgi: STRING = "libfcgi"
|
||||
|
||||
launch_libfcgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER
|
||||
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G]
|
||||
do
|
||||
create launcher.make_and_launch (a_service, opts)
|
||||
create launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ note
|
||||
revision: "$Revision: 36 $"
|
||||
|
||||
class
|
||||
APPLICATION_LAUNCHER
|
||||
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
APPLICATION_LAUNCHER_I
|
||||
APPLICATION_LAUNCHER_I [G]
|
||||
|
||||
feature -- Custom
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ note
|
||||
revision: "$Revision: 36 $"
|
||||
|
||||
deferred class
|
||||
APPLICATION_LAUNCHER_I
|
||||
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||
|
||||
feature -- Execution
|
||||
|
||||
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||
local
|
||||
launcher: WSF_SERVICE_LAUNCHER
|
||||
launcher: WSF_SERVICE_LAUNCHER [G]
|
||||
do
|
||||
create {WSF_DEFAULT_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
|
||||
create {WSF_DEFAULT_SERVICE_LAUNCHER [G]} launcher.make_and_launch (opts)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
27
examples/debug/src/ewf_debug_execution.e
Normal file
27
examples/debug/src/ewf_debug_execution.e
Normal file
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Summary description for {EWF_DEBUG_EXECUTION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
EWF_DEBUG_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute
|
||||
local
|
||||
dbg: WSF_DEBUG_HANDLER
|
||||
do
|
||||
response.put_error ("DEBUG uri=" + request.request_uri + "%N")
|
||||
create dbg.make
|
||||
dbg.execute_starts_with ("", request, response)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -14,7 +14,7 @@ inherit
|
||||
initialize
|
||||
end
|
||||
|
||||
APPLICATION_LAUNCHER
|
||||
APPLICATION_LAUNCHER [EWF_DEBUG_EXECUTION]
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
@@ -30,14 +30,14 @@ feature {NONE} -- Initialization
|
||||
-- set_service_option ("base", "/www-debug/debug_service.fcgi/")
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
dbg: WSF_DEBUG_HANDLER
|
||||
do
|
||||
res.put_error ("DEBUG" + req.request_uri + "%N")
|
||||
create dbg.make
|
||||
dbg.execute_starts_with ("", req, res)
|
||||
end
|
||||
-- execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- local
|
||||
-- dbg: WSF_DEBUG_HANDLER
|
||||
-- do
|
||||
-- res.put_error ("OH NO uri=" + req.request_uri + "%N")
|
||||
-- create dbg.make
|
||||
-- dbg.execute_starts_with ("", req, res)
|
||||
-- end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -7,17 +7,16 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<precompile name="vision2-pre" location="$ISE_PRECOMP\vision2-mt-safe.ecf"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<library name="vision2" location="$ISE_LIBRARY\library\vision2\vision2-safe.ecf"/>
|
||||
<library name="web_browser" location="$ISE_LIBRARY\library\web_browser\web_browser-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<library name="wsf_nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
|
||||
<library name="wsf_nino_connector" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
|
||||
<cluster name="src" location=".\src" recursive="true">
|
||||
<library name="wsf_standalone" location="..\..\library\server\wsf\connector\standalone-safe.ecf"/>
|
||||
<library name="wsf_standalone_connector" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
|
||||
239
examples/desktop_app/src/app_embedded_web_execution.e
Normal file
239
examples/desktop_app/src/app_embedded_web_execution.e
Normal file
@@ -0,0 +1,239 @@
|
||||
note
|
||||
description: "Summary description for {APP_EMBEDDED_WEB_EXECUTION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
APP_EMBEDDED_WEB_EXECUTION
|
||||
|
||||
inherit
|
||||
EMBEDDED_WEB_EXECUTION
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
Precursor
|
||||
create request_exit_operation_actions
|
||||
local_connection_restriction_enabled := True
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
|
||||
|
||||
execute
|
||||
-- Execute the request
|
||||
-- See `request.input' for input stream
|
||||
-- `request.meta_variables' for the CGI meta variable
|
||||
-- and `response' for output buffer
|
||||
local
|
||||
router: WSF_ROUTER
|
||||
sess: detachable WSF_ROUTER_SESSION
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
fs: WSF_FILE_SYSTEM_HANDLER
|
||||
req: like request
|
||||
do
|
||||
req := request
|
||||
|
||||
create router.make (3)
|
||||
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
|
||||
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
|
||||
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
|
||||
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
|
||||
router.handle ("/files", fs)
|
||||
create sess
|
||||
router.dispatch (req, response, sess)
|
||||
if not sess.dispatched then
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
|
||||
m.set_body (b)
|
||||
response.send (m)
|
||||
end
|
||||
end
|
||||
|
||||
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
l_name: READABLE_STRING_32
|
||||
do
|
||||
if attached {WSF_STRING} req.item ("var") as p_name then
|
||||
l_name := p_name.value
|
||||
else
|
||||
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
|
||||
end
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
if l_name.is_case_insensitive_equal_general ("start") then
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
|
||||
elseif l_name.is_case_insensitive_equal_general ("js") then
|
||||
b.append ("[
|
||||
<div id="myDiv"><h2>Let AJAX change this text</h2>
|
||||
<button type="button" onclick="loadXMLDoc()">Change Content</button>
|
||||
</div>
|
||||
]")
|
||||
m.add_javascript_content ("[
|
||||
function loadXMLDoc()
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{// code for IE7+, Firefox, Chrome, Opera, Safari
|
||||
xmlhttp=new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{// code for IE6, IE5
|
||||
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState==4 && xmlhttp.status==200)
|
||||
{
|
||||
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET","/test/ajax.txt",true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
]")
|
||||
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
|
||||
b := "This is AJAX response ... from " + req.absolute_script_url ("")
|
||||
end
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
end
|
||||
|
||||
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING_8
|
||||
p: WSF_PAGE_RESPONSE
|
||||
v: STRING_8
|
||||
do
|
||||
create s.make (2048)
|
||||
s.append ("**DEBUG**%N")
|
||||
req.set_raw_input_data_recorded (True)
|
||||
|
||||
append_iterable_to ("Meta variables:", req.meta_variables, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Path parameters", req.path_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Query parameters", req.query_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Form parameters", req.form_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
if attached req.content_type as l_type then
|
||||
s.append ("Content: type=" + l_type.debug_output)
|
||||
s.append (" length=")
|
||||
s.append_natural_64 (req.content_length_value)
|
||||
s.append_character ('%N')
|
||||
create v.make (req.content_length_value.to_integer_32)
|
||||
req.read_input_data_into (v)
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
create p.make_with_body (s)
|
||||
p.header.put_content_type_text_plain
|
||||
res.send (p)
|
||||
end
|
||||
|
||||
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
do
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/bye") + "%">Click to confirm exit operation</a></li>")
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
if attached {separate WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]} req.wgi_connector as conn then
|
||||
shutdown_server (conn)
|
||||
end
|
||||
request_exit_operation_actions.call (Void)
|
||||
end
|
||||
|
||||
shutdown_server (conn: separate WGI_STANDALONE_CONNECTOR [WGI_EXECUTION])
|
||||
do
|
||||
conn.shutdown_server
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
|
||||
local
|
||||
n: INTEGER
|
||||
t: READABLE_STRING_8
|
||||
v: READABLE_STRING_8
|
||||
do
|
||||
s.append (a_title)
|
||||
s.append_character (':')
|
||||
if it /= Void then
|
||||
across it as c loop
|
||||
n := n + 1
|
||||
end
|
||||
if n = 0 then
|
||||
s.append (" empty")
|
||||
s.append_character ('%N')
|
||||
else
|
||||
s.append_character ('%N')
|
||||
across
|
||||
it as c
|
||||
loop
|
||||
s.append (" - ")
|
||||
s.append (c.item.url_encoded_name)
|
||||
t := c.item.generating_type
|
||||
if t.same_string ("WSF_STRING") then
|
||||
else
|
||||
s.append_character (' ')
|
||||
s.append_character ('{')
|
||||
s.append (t)
|
||||
s.append_character ('}')
|
||||
end
|
||||
s.append_character ('=')
|
||||
v := c.item.string_representation.as_string_8
|
||||
if v.has ('%N') then
|
||||
s.append_character ('%N')
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
else
|
||||
s.append (v)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
s.append (" none")
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -8,223 +8,11 @@ class
|
||||
APP_EMBEDDED_WEB_SERVICE
|
||||
|
||||
inherit
|
||||
EMBEDDED_WEB_SERVICE
|
||||
redefine
|
||||
make
|
||||
end
|
||||
EMBEDDED_WEB_SERVICE [APP_EMBEDDED_WEB_EXECUTION]
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
Precursor
|
||||
create request_exit_operation_actions
|
||||
local_connection_restriction_enabled := True
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
|
||||
|
||||
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
|
||||
local
|
||||
router: WSF_ROUTER
|
||||
sess: detachable WSF_ROUTER_SESSION
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
fs: WSF_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
create router.make (3)
|
||||
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
|
||||
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
|
||||
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
|
||||
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
|
||||
router.handle ("/files", fs)
|
||||
create sess
|
||||
router.dispatch (req, res, sess)
|
||||
if not sess.dispatched then
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
end
|
||||
end
|
||||
|
||||
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
l_name: READABLE_STRING_32
|
||||
do
|
||||
if attached {WSF_STRING} req.item ("var") as p_name then
|
||||
l_name := p_name.value
|
||||
else
|
||||
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
|
||||
end
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
if l_name.is_case_insensitive_equal_general ("start") then
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
|
||||
elseif l_name.is_case_insensitive_equal_general ("js") then
|
||||
b.append ("[
|
||||
<div id="myDiv"><h2>Let AJAX change this text</h2>
|
||||
<button type="button" onclick="loadXMLDoc()">Change Content</button>
|
||||
</div>
|
||||
]")
|
||||
m.add_javascript_content ("[
|
||||
function loadXMLDoc()
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{// code for IE7+, Firefox, Chrome, Opera, Safari
|
||||
xmlhttp=new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{// code for IE6, IE5
|
||||
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState==4 && xmlhttp.status==200)
|
||||
{
|
||||
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET","/test/ajax.txt",true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
]")
|
||||
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
|
||||
b := "This is AJAX response ... from " + req.absolute_script_url ("")
|
||||
end
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
end
|
||||
|
||||
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING_8
|
||||
p: WSF_PAGE_RESPONSE
|
||||
v: STRING_8
|
||||
do
|
||||
create s.make (2048)
|
||||
s.append ("**DEBUG**%N")
|
||||
req.set_raw_input_data_recorded (True)
|
||||
|
||||
append_iterable_to ("Meta variables:", req.meta_variables, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Path parameters", req.path_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Query parameters", req.query_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Form parameters", req.form_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
if attached req.content_type as l_type then
|
||||
s.append ("Content: type=" + l_type.debug_output)
|
||||
s.append (" length=")
|
||||
s.append_natural_64 (req.content_length_value)
|
||||
s.append_character ('%N')
|
||||
create v.make (req.content_length_value.to_integer_32)
|
||||
req.read_input_data_into (v)
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
create p.make_with_body (s)
|
||||
p.header.put_content_type_text_plain
|
||||
res.send (p)
|
||||
end
|
||||
|
||||
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
do
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
if attached {WGI_NINO_CONNECTOR} req.wgi_connector as nino then
|
||||
nino.server.shutdown_server
|
||||
end
|
||||
request_exit_operation_actions.call (Void)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
|
||||
local
|
||||
n: INTEGER
|
||||
t: READABLE_STRING_8
|
||||
v: READABLE_STRING_8
|
||||
do
|
||||
s.append (a_title)
|
||||
s.append_character (':')
|
||||
if it /= Void then
|
||||
across it as c loop
|
||||
n := n + 1
|
||||
end
|
||||
if n = 0 then
|
||||
s.append (" empty")
|
||||
s.append_character ('%N')
|
||||
else
|
||||
s.append_character ('%N')
|
||||
across
|
||||
it as c
|
||||
loop
|
||||
s.append (" - ")
|
||||
s.append (c.item.url_encoded_name)
|
||||
t := c.item.generating_type
|
||||
if t.same_string ("WSF_STRING") then
|
||||
else
|
||||
s.append_character (' ')
|
||||
s.append_character ('{')
|
||||
s.append (t)
|
||||
s.append_character ('}')
|
||||
end
|
||||
s.append_character ('=')
|
||||
v := c.item.string_representation.as_string_8
|
||||
if v.has ('%N') then
|
||||
s.append_character ('%N')
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
else
|
||||
s.append (v)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
s.append (" none")
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -24,18 +24,17 @@ feature {NONE} -- Initialization
|
||||
-- then launch the application.
|
||||
local
|
||||
l_win: like main_window
|
||||
l_embeded_services: APP_EMBEDDED_WEB_SERVICE
|
||||
l_embedded_service: APP_EMBEDDED_WEB_SERVICE
|
||||
do
|
||||
default_create
|
||||
create l_win.make
|
||||
main_window := l_win
|
||||
l_win.show
|
||||
create l_embeded_services.make
|
||||
l_embeded_services.set_port_number (0) -- Use first available port number
|
||||
create l_embedded_service.make
|
||||
l_embedded_service.set_port_number (0) -- Use first available port number
|
||||
|
||||
l_embeded_services.on_launched_actions.force (agent on_web_service_launched (l_win))
|
||||
l_embeded_services.request_exit_operation_actions.force (agent on_quit)
|
||||
l_embeded_services.launch
|
||||
l_embedded_service.on_launched_actions.force (agent on_web_service_launched (l_win, l_embedded_service))
|
||||
l_embedded_service.launch
|
||||
launch
|
||||
end
|
||||
|
||||
@@ -46,11 +45,44 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
end
|
||||
|
||||
on_web_service_launched (a_win: attached like main_window)
|
||||
on_web_service_launched (a_win: attached like main_window; s: APP_EMBEDDED_WEB_SERVICE)
|
||||
do
|
||||
add_idle_action_kamikaze (agent wait_for_termination (s, Void))
|
||||
add_idle_action_kamikaze (agent a_win.open_link)
|
||||
end
|
||||
|
||||
wait_for_termination (s: APP_EMBEDDED_WEB_SERVICE; a_timeout: detachable EV_TIMEOUT)
|
||||
local
|
||||
t: detachable EV_TIMEOUT
|
||||
do
|
||||
t := a_timeout
|
||||
if t /= Void then
|
||||
t.set_interval (0)
|
||||
end
|
||||
if
|
||||
attached s.observer as obs and then
|
||||
observer_has_terminaded (obs)
|
||||
then
|
||||
if t /= Void then
|
||||
t.destroy
|
||||
end
|
||||
on_quit
|
||||
else
|
||||
if t = Void then
|
||||
create t
|
||||
t.actions.extend (agent wait_for_termination (s, t))
|
||||
else
|
||||
t.set_interval (1_000)
|
||||
end
|
||||
t.set_interval (1_000)
|
||||
end
|
||||
end
|
||||
|
||||
observer_has_terminaded (obs: separate WGI_STANDALONE_SERVER_OBSERVER): BOOLEAN
|
||||
do
|
||||
Result := obs.terminated
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
main_window: detachable MAIN_WINDOW
|
||||
|
||||
63
examples/desktop_app/src/service/embedded_web_execution.e
Normal file
63
examples/desktop_app/src/service/embedded_web_execution.e
Normal file
@@ -0,0 +1,63 @@
|
||||
note
|
||||
description: "Summary description for {EMBEDDED_WEB_EXECUTION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EMBEDDED_WEB_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
rename
|
||||
execute as execute_embedded
|
||||
end
|
||||
|
||||
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
execute_embedded
|
||||
-- Execute the request
|
||||
-- See `request.input' for input stream
|
||||
-- `request.meta_variables' for the CGI meta variable
|
||||
-- and `response' for output buffer
|
||||
local
|
||||
filter: WSF_AGENT_FILTER
|
||||
m: WSF_PAGE_RESPONSE
|
||||
do
|
||||
if local_connection_restriction_enabled then
|
||||
if
|
||||
attached request.remote_addr as l_remote_addr and then
|
||||
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
|
||||
then
|
||||
execute
|
||||
else
|
||||
create m.make_with_body ("Only local connection is allowed")
|
||||
m.set_status_code (403) -- Forbidden
|
||||
response.send (m)
|
||||
end
|
||||
else
|
||||
execute
|
||||
end
|
||||
end
|
||||
|
||||
execute
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
local_connection_restriction_enabled: BOOLEAN
|
||||
-- Accept only local connection?
|
||||
--| based on 127.0.0.1 IP
|
||||
--| TO IMPROVE
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_local_connection_restriction_enabled (b: BOOLEAN)
|
||||
do
|
||||
local_connection_restriction_enabled := b
|
||||
end
|
||||
|
||||
end
|
||||
@@ -5,19 +5,10 @@ note
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EMBEDDED_WEB_SERVICE
|
||||
EMBEDDED_WEB_SERVICE [G -> EMBEDDED_WEB_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
THREAD
|
||||
rename
|
||||
make as make_thread,
|
||||
execute as execute_thread
|
||||
end
|
||||
|
||||
WSF_SERVICE
|
||||
rename
|
||||
execute as execute_embedded
|
||||
end
|
||||
|
||||
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
|
||||
|
||||
@@ -25,90 +16,35 @@ feature -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
make_thread
|
||||
create on_launched_actions
|
||||
end
|
||||
|
||||
feature {NONE} -- Execution
|
||||
feature -- Execution
|
||||
|
||||
execute_embedded (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
|
||||
launch
|
||||
local
|
||||
filter: WSF_AGENT_FILTER
|
||||
m: WSF_PAGE_RESPONSE
|
||||
do
|
||||
if local_connection_restriction_enabled then
|
||||
if
|
||||
attached req.remote_addr as l_remote_addr and then
|
||||
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
|
||||
then
|
||||
execute (req, res)
|
||||
else
|
||||
create m.make_with_body ("Only local connection is allowed")
|
||||
m.set_status_code (403) -- Forbidden
|
||||
res.send (m)
|
||||
end
|
||||
else
|
||||
execute (req, res)
|
||||
end
|
||||
end
|
||||
|
||||
execute_thread
|
||||
local
|
||||
nino: WSF_NINO_SERVICE_LAUNCHER
|
||||
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
|
||||
opts: WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
do
|
||||
create opts.default_create
|
||||
opts.set_verbose (True)
|
||||
opts.set_option ("port", port_number)
|
||||
create nino.make (Current, opts)
|
||||
nino.on_launched_actions.force (agent on_launched)
|
||||
nino.launch
|
||||
create launcher.make (opts)
|
||||
observer := launcher.connector.observer
|
||||
launcher.on_launched_actions.force (agent on_launched)
|
||||
launcher.launch
|
||||
end
|
||||
|
||||
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
|
||||
deferred
|
||||
end
|
||||
observer: detachable separate WGI_STANDALONE_SERVER_OBSERVER
|
||||
|
||||
on_launched (conn: WGI_CONNECTOR)
|
||||
on_launched (conn: WGI_STANDALONE_CONNECTOR [G])
|
||||
do
|
||||
if attached {WGI_NINO_CONNECTOR} conn as nino then
|
||||
set_port_number (nino.port)
|
||||
end
|
||||
set_port_number (conn.port)
|
||||
on_launched_actions.call (Void)
|
||||
end
|
||||
|
||||
feature -- Control
|
||||
|
||||
wait
|
||||
-- Wait for server to be terminated.
|
||||
do
|
||||
join
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
on_launched_actions: ACTION_SEQUENCE [TUPLE]
|
||||
|
||||
feature -- Status report
|
||||
|
||||
local_connection_restriction_enabled: BOOLEAN
|
||||
-- Accept only local connection?
|
||||
--| based on 127.0.0.1 IP
|
||||
--| TO IMPROVE
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_local_connection_restriction_enabled (b: BOOLEAN)
|
||||
do
|
||||
local_connection_restriction_enabled := b
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -11,15 +11,25 @@ feature -- Access
|
||||
|
||||
port_number: INTEGER
|
||||
do
|
||||
Result := port_number_cell.item
|
||||
Result := separate_port_number (port_number_cell)
|
||||
end
|
||||
|
||||
set_port_number (a_port: like port_number)
|
||||
do
|
||||
port_number_cell.replace (a_port)
|
||||
separate_set_port_number (port_number_cell, a_port)
|
||||
end
|
||||
|
||||
port_number_cell: CELL [INTEGER]
|
||||
separate_port_number (cl: like port_number_cell): like port_number
|
||||
do
|
||||
Result := cl.item
|
||||
end
|
||||
|
||||
separate_set_port_number (cl: like port_number_cell; a_port: like port_number)
|
||||
do
|
||||
cl.replace (a_port)
|
||||
end
|
||||
|
||||
port_number_cell: separate CELL [INTEGER]
|
||||
once ("process")
|
||||
create Result.put (0)
|
||||
end
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E" library_target="filter">
|
||||
<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="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E" library_target="filter">
|
||||
<target name="common">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<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="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="true"/>
|
||||
<library name="http" location="../../library/network/protocol/http/http-safe.ecf" readonly="true"/>
|
||||
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="true"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="true"/>
|
||||
<library name="wsf_router_context" location="..\..\library\server\wsf\wsf_router_context-safe.ecf" readonly="true"/>
|
||||
<library name="wsf_extension" location="..\..\library\server\wsf\wsf_extension-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="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="true"/>
|
||||
<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_nino" extends="common">
|
||||
<root class="FILTER_SERVER" feature="make"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="true"/>
|
||||
<cluster name="filter" location="src\" recursive="true"/>
|
||||
</target>
|
||||
<target name="filter_standalone" extends="common">
|
||||
<root class="FILTER_SERVER" feature="make"/>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<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"/>
|
||||
|
||||
@@ -24,26 +24,33 @@ feature -- Initialization
|
||||
|
||||
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
|
||||
local
|
||||
n: like {USER}.name
|
||||
do
|
||||
if a_id > 0 then
|
||||
Result := users.item (a_id)
|
||||
Result := user_by_id (a_id)
|
||||
elseif a_name /= Void then
|
||||
n := a_name.as_string_8
|
||||
across
|
||||
users as c
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
if attached c.item as u and then u.name.same_string (n) then
|
||||
Result := u
|
||||
end
|
||||
end
|
||||
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)))
|
||||
@@ -52,6 +59,6 @@ feature -- Access
|
||||
users: HASH_TABLE [USER, INTEGER]
|
||||
|
||||
;note
|
||||
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
|
||||
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -48,18 +48,31 @@ feature {NONE} -- Implementation
|
||||
-- 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
|
||||
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"User%"")
|
||||
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-2014, Olivier Ligot, Jocelyn Fiat and others"
|
||||
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -8,18 +8,7 @@ class
|
||||
FILTER_SERVER
|
||||
|
||||
inherit
|
||||
ANY
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
|
||||
WSF_ROUTED_SERVICE
|
||||
undefine
|
||||
execute
|
||||
end
|
||||
|
||||
WSF_FILTERED_SERVICE
|
||||
|
||||
SHARED_EJSON
|
||||
WSF_DEFAULT_SERVICE [FILTER_SERVER_EXECUTION]
|
||||
|
||||
create
|
||||
make
|
||||
@@ -31,9 +20,6 @@ feature {NONE} -- Initialization
|
||||
l_message: STRING
|
||||
l_factory: INET_ADDRESS_FACTORY
|
||||
do
|
||||
initialize_router
|
||||
initialize_filter
|
||||
initialize_json
|
||||
set_service_option ("port", port)
|
||||
create l_message.make_empty
|
||||
l_message.append_string ("Launching filter server at ")
|
||||
@@ -46,60 +32,13 @@ feature {NONE} -- Initialization
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
create_filter
|
||||
-- Create `filter'
|
||||
do
|
||||
create {WSF_CORS_FILTER} filter
|
||||
end
|
||||
|
||||
setup_filter
|
||||
-- Setup `filter'
|
||||
local
|
||||
l_routing_filter: WSF_ROUTING_FILTER
|
||||
l_logging_filter: WSF_LOGGING_FILTER
|
||||
do
|
||||
create l_routing_filter.make (router)
|
||||
l_routing_filter.set_execute_default_action (agent execute_default)
|
||||
filter.set_next (l_routing_filter)
|
||||
|
||||
create l_logging_filter
|
||||
l_routing_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_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
|
||||
end
|
||||
|
||||
initialize_json
|
||||
-- Initialize `json'.
|
||||
do
|
||||
json.add_converter (create {JSON_USER_CONVERTER}.make)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
port: INTEGER = 9090
|
||||
-- Port number
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat and others"
|
||||
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
|
||||
|
||||
82
examples/filter/src/filter_server_execution.e
Normal file
82
examples/filter/src/filter_server_execution.e
Normal 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_with_request_methods ("/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
|
||||
@@ -41,7 +41,7 @@ feature -- Basic operations
|
||||
local
|
||||
id : STRING
|
||||
do
|
||||
if attached req.orig_path_info as orig_path then
|
||||
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
|
||||
@@ -86,12 +86,14 @@ feature {NONE} -- Implementation
|
||||
retrieve_user (id: STRING) : detachable USER
|
||||
-- Retrieve the user by id if it exist, in other case, Void
|
||||
do
|
||||
if id.is_integer and then Db_access.users.has (id.to_integer) then
|
||||
Result := db_access.users.item (id.to_integer)
|
||||
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-2013, Olivier Ligot, Jocelyn Fiat and others"
|
||||
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
|
||||
@@ -6,19 +6,7 @@ note
|
||||
class RESTBUCKS_SERVER
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SKELETON_SERVICE
|
||||
undefine
|
||||
requires_proxy
|
||||
end
|
||||
|
||||
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
|
||||
|
||||
WSF_HANDLER_HELPER
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
WSF_DEFAULT_SERVICE [RESTBUCKS_SERVER_EXECUTION]
|
||||
|
||||
create
|
||||
make
|
||||
@@ -27,26 +15,12 @@ feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
initialize_router
|
||||
set_service_option ("port", 9090)
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
order_handler: ORDER_HANDLER
|
||||
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
|
||||
do
|
||||
create order_handler.make_with_router (router)
|
||||
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
|
||||
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
|
||||
create doc.make_hidden (router)
|
||||
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla and others"
|
||||
copyright: "2011-2015, Javier Velilla and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
57
examples/restbucksCRUD/src/restbucks_server_execution.e
Normal file
57
examples/restbucksCRUD/src/restbucks_server_execution.e
Normal file
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description : "REST Buck server"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class RESTBUCKS_SERVER_EXECUTION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SKELETON_EXECUTION
|
||||
undefine
|
||||
requires_proxy
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
WSF_ROUTED_URI_TEMPLATE_HELPER
|
||||
|
||||
WSF_HANDLER_HELPER
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
Precursor
|
||||
initialize_router
|
||||
end
|
||||
|
||||
setup_router
|
||||
local
|
||||
order_handler: ORDER_HANDLER
|
||||
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
|
||||
do
|
||||
create order_handler.make_with_router (router)
|
||||
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
|
||||
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
|
||||
create doc.make_hidden (router)
|
||||
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Javier Velilla 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,7 +7,7 @@ class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
@@ -23,14 +23,6 @@ feature {NONE} -- Initialization
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
|
||||
res.put_string ("Hello World")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
34
examples/simple/application_execution.e
Normal file
34
examples/simple/application_execution.e
Normal file
@@ -0,0 +1,34 @@
|
||||
note
|
||||
description : "simple application execution"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
execute
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
-- To send a response we need to setup, the status code and
|
||||
-- the response headers.
|
||||
s := "Hello World!"
|
||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
|
||||
response.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
response.header.put_content_type_text_html
|
||||
response.header.put_content_length (s.count)
|
||||
if attached request.http_connection as l_connection and then l_connection.is_case_insensitive_equal_general ("keep-alive") then
|
||||
response.header.put_header_key_value ("Connection", "keep-alive")
|
||||
end
|
||||
response.put_string (s)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,21 +1,30 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
|
||||
<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="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
|
||||
<target name="common" abstract="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
</target>
|
||||
<target name="simple_standalone" extends="common">
|
||||
<root class="APPLICATION" feature="make_and_launch"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<cluster name="simple" location=".\" recursive="true"/>
|
||||
</target>
|
||||
<target name="simple_nino" extends="common">
|
||||
<root class="APPLICATION" feature="make_and_launch"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
@@ -23,7 +32,7 @@
|
||||
</target>
|
||||
<target name="simple_cgi" extends="common">
|
||||
<root class="APPLICATION" feature="make_and_launch"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
|
||||
@@ -31,12 +40,12 @@
|
||||
</target>
|
||||
<target name="simple_libfcgi" extends="common">
|
||||
<root class="APPLICATION" feature="make_and_launch"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="default_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf"/>
|
||||
<cluster name="simple" location=".\" recursive="true"/>
|
||||
</target>
|
||||
<target name="simple" extends="simple_nino">
|
||||
<target name="simple" extends="simple_standalone">
|
||||
</target>
|
||||
</system>
|
||||
|
||||
12
examples/simple_file/404.html
Normal file
12
examples/simple_file/404.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>404 not found!</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>404 not found!</h1>
|
||||
This is a static html file served by EWF.
|
||||
<img src="ewf.png"/>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
examples/simple_file/ewf.png
Normal file
BIN
examples/simple_file/ewf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -1,13 +1,13 @@
|
||||
<html>
|
||||
<head>
|
||||
Eiffel REST services
|
||||
<title>EWF simple_file example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Welcome to the Eiffel REST services site, here you will find a lot of <br/>
|
||||
resources about REST and our solution
|
||||
|
||||
|
||||
<h1>EWF simple_file example</h1>
|
||||
<p>This is a static html file served by EWF.</p>
|
||||
<p>Try to <a href="nowhere.html">get lost</a>.</p>
|
||||
<a href="ewf.png"><img src="ewf.png"/></a>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -7,18 +7,20 @@ class
|
||||
SERVICE_FILE
|
||||
|
||||
inherit
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [SERVICE_FILE_EXECUTION]
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: WSF_FILE_RESPONSE
|
||||
initialize
|
||||
do
|
||||
create f.make_html ("home.html")
|
||||
res.send (f)
|
||||
Precursor
|
||||
set_service_option ("port", 9090)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
|
||||
<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="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
|
||||
<target name="service_file">
|
||||
<root class="SERVICE_FILE" feature="make_and_launch"/>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="scoop"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="http" location="../../library/network/protocol/http/http-safe.ecf"/>
|
||||
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf"/>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<cluster name="service_file" location=".\" recursive="true">
|
||||
<file_rule>
|
||||
|
||||
35
examples/simple_file/service_file_execution.e
Normal file
35
examples/simple_file/service_file_execution.e
Normal file
@@ -0,0 +1,35 @@
|
||||
note
|
||||
description: "Simple file execution, serving home.html, ewf.png and 404.html"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SERVICE_FILE_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_EXECUTION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
execute
|
||||
local
|
||||
mesg: WSF_RESPONSE_MESSAGE
|
||||
not_found: WSF_NOT_FOUND_RESPONSE
|
||||
do
|
||||
if request.path_info.is_case_insensitive_equal_general ("/") then
|
||||
create {WSF_FILE_RESPONSE} mesg.make_html ("home.html")
|
||||
elseif request.path_info.is_case_insensitive_equal_general ("/ewf.png") then
|
||||
create {WSF_FILE_RESPONSE} mesg.make_with_content_type ({HTTP_MIME_TYPES}.image_png ,"ewf.png")
|
||||
else
|
||||
create not_found.make (request)
|
||||
not_found.add_suggested_location (request.absolute_script_url (""), "Home", "Back to home page")
|
||||
|
||||
mesg := not_found
|
||||
end
|
||||
response.send (mesg)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -10,16 +10,7 @@ class
|
||||
inherit
|
||||
ANY
|
||||
|
||||
WSF_ROUTED_SKELETON_SERVICE
|
||||
undefine
|
||||
requires_proxy
|
||||
end
|
||||
|
||||
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
WSF_DEFAULT_SERVICE
|
||||
WSF_DEFAULT_SERVICE [IMAGE_UPLOADER_EXECUTION]
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
@@ -31,224 +22,12 @@ feature {NONE} -- Initialization
|
||||
make
|
||||
-- Initialize Current
|
||||
do
|
||||
initialize_router
|
||||
|
||||
|
||||
-- To use particular port number (as 9090) with Nino connector
|
||||
-- Uncomment the following line
|
||||
set_service_option ("port", 9090)
|
||||
make_and_launch
|
||||
end
|
||||
|
||||
setup_router
|
||||
-- Setup router
|
||||
local
|
||||
www: WSF_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
|
||||
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
|
||||
|
||||
create www.make_with_path (document_root)
|
||||
www.set_directory_index (<<"index.html">>)
|
||||
www.set_not_found_handler (agent execute_not_found)
|
||||
router.handle_with_request_methods ("", www, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Configuration
|
||||
|
||||
document_root: PATH
|
||||
-- Document root to look for files or directories
|
||||
once
|
||||
Result := execution_environment.current_working_path.extended ("htdocs")
|
||||
ensure
|
||||
not Result.name.ends_with (Operating_environment.directory_separator.out)
|
||||
end
|
||||
|
||||
files_root: PATH
|
||||
-- Uploaded files will be stored in `files_root' folder
|
||||
once
|
||||
Result := document_root.extended ("files")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_not_found (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- `uri' is not found, redirect to default page
|
||||
do
|
||||
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html")
|
||||
end
|
||||
|
||||
execute_upload (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Upload page is requested, either GET or POST
|
||||
-- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images
|
||||
-- On POST display the uploaded files
|
||||
local
|
||||
l_body: STRING_8
|
||||
l_safe_filename: STRING_8
|
||||
fn: PATH
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
n: INTEGER
|
||||
do
|
||||
if req.is_request_method ("GET") or else not req.has_uploaded_file then
|
||||
create page.make
|
||||
page.set_title ("EWF: Upload file")
|
||||
page.add_style (req.script_url ("style.css"), "all")
|
||||
create l_body.make_empty
|
||||
page.set_body (l_body)
|
||||
l_body.append ("<h1>EWF: Upload image file</h1>%N")
|
||||
l_body.append ("<form action=%""+ req.script_url ("/upload") +"%" method=%"POST%" enctype=%"multipart/form-data%">%N")
|
||||
if attached {WSF_STRING} req.query_parameter ("nb") as p_nb and then p_nb.is_integer then
|
||||
n := p_nb.integer_value
|
||||
else
|
||||
n := 1
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("demo") as p_demo then
|
||||
fn := document_root.extended (p_demo.value)
|
||||
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.name) +"%"></br>%N")
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
n = 0
|
||||
loop
|
||||
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" accept=%"image/*%"></br>%N")
|
||||
n := n - 1
|
||||
end
|
||||
l_body.append (" <input type=%"submit%" value=%"Upload%"/>%N</form>")
|
||||
res.send (page)
|
||||
else
|
||||
create l_body.make (255)
|
||||
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
|
||||
l_body.append ("<ul>")
|
||||
n := 0
|
||||
across
|
||||
req.uploaded_files as c
|
||||
loop
|
||||
n := n + 1
|
||||
l_body.append ("<li>")
|
||||
l_body.append ("<div>" + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "</div>")
|
||||
l_safe_filename := c.item.safe_filename
|
||||
fn := files_root.extended (l_safe_filename)
|
||||
if c.item.move_to (fn.name) then
|
||||
if c.item.content_type.starts_with ("image") then
|
||||
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%"><img src=%"../files/"+ l_safe_filename +"%" /></a>")
|
||||
else
|
||||
l_body.append ("File " + html_encode (c.item.filename) + " is not a supported image<br/>%N")
|
||||
end
|
||||
end
|
||||
l_body.append ("</li>")
|
||||
end
|
||||
|
||||
l_body.append ("</ul>")
|
||||
|
||||
create page.make
|
||||
page.set_title ("EWF: uploaded image")
|
||||
page.add_style ("../style.css", "all")
|
||||
page.set_body (l_body)
|
||||
res.send (page)
|
||||
end
|
||||
end
|
||||
|
||||
execute_upload_put (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Upload page is requested, PUT
|
||||
require
|
||||
is_put_request_method: req.is_put_request_method
|
||||
local
|
||||
l_body: STRING_8
|
||||
l_safe_filename: detachable READABLE_STRING_32
|
||||
fn: PATH
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
n: INTEGER
|
||||
do
|
||||
create l_body.make (255)
|
||||
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
|
||||
l_body.append ("<ul>")
|
||||
n := 0
|
||||
if attached {WSF_STRING} req.path_parameter ("name") as p_name then
|
||||
l_safe_filename := p_name.value
|
||||
end
|
||||
if l_safe_filename = Void or else l_safe_filename.is_empty then
|
||||
l_safe_filename := "input_data"
|
||||
end
|
||||
if n = 0 and req.content_length_value > 0 then
|
||||
if attached new_temporary_output_file ("tmp-uploaded-file_" + n.out) as f then
|
||||
req.read_input_data_into_file (f)
|
||||
f.close
|
||||
fn := files_root.extended (l_safe_filename)
|
||||
f.rename_file (fn.name)
|
||||
l_body.append ("<li>")
|
||||
l_body.append ("<div>Input data : size=" + f.count.out + " (" + req.content_length_value.out + ")</div>")
|
||||
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%">"+ html_encode (l_safe_filename) +"</a>")
|
||||
l_body.append ("</li>")
|
||||
end
|
||||
end
|
||||
l_body.append ("</ul>")
|
||||
|
||||
create page.make
|
||||
page.set_title ("EWF: uploaded image")
|
||||
page.add_style ("../style.css", "all")
|
||||
page.set_body (l_body)
|
||||
res.send (page)
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Encoder
|
||||
|
||||
new_temporary_output_file (n: detachable READABLE_STRING_8): detachable FILE
|
||||
local
|
||||
bp: detachable PATH
|
||||
d: DIRECTORY
|
||||
i: INTEGER
|
||||
do
|
||||
create bp.make_current
|
||||
create d.make_with_path (bp)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
if n /= Void then
|
||||
bp := bp.extended ("tmp-download-" + n)
|
||||
else
|
||||
bp := bp.extended ("tmp")
|
||||
end
|
||||
from
|
||||
i := 0
|
||||
until
|
||||
Result /= Void or i > 100
|
||||
loop
|
||||
i := i + 1
|
||||
create {RAW_FILE} Result.make_with_path (bp.appended ("__" + i.out))
|
||||
if Result.exists then
|
||||
Result := Void
|
||||
else
|
||||
Result.open_write
|
||||
end
|
||||
end
|
||||
ensure
|
||||
Result /= Void implies Result.is_open_write
|
||||
end
|
||||
|
||||
url_encode (s: READABLE_STRING_32): STRING_8
|
||||
-- URL Encode `s' as Result
|
||||
do
|
||||
Result := url_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
html_encode (s: READABLE_STRING_32): STRING_8
|
||||
-- HTML Encode `s' as Result
|
||||
do
|
||||
Result := html_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
html_encoder: HTML_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
242
examples/upload_image/src/image_uploader_execution.e
Normal file
242
examples/upload_image/src/image_uploader_execution.e
Normal file
@@ -0,0 +1,242 @@
|
||||
note
|
||||
description: "Summary description for {IMAGE_UPLOADER_EXECUTION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
IMAGE_UPLOADER_EXECUTION
|
||||
|
||||
inherit
|
||||
WSF_ROUTED_SKELETON_EXECUTION
|
||||
undefine
|
||||
requires_proxy
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
WSF_ROUTED_URI_TEMPLATE_HELPER
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
Precursor
|
||||
initialize_router
|
||||
end
|
||||
|
||||
setup_router
|
||||
-- Setup router
|
||||
local
|
||||
www: WSF_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
|
||||
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
|
||||
|
||||
create www.make_with_path (document_root)
|
||||
www.set_directory_index (<<"index.html">>)
|
||||
www.set_not_found_handler (agent execute_not_found)
|
||||
router.handle_with_request_methods ("", www, router.methods_GET)
|
||||
end
|
||||
|
||||
feature -- Configuration
|
||||
|
||||
document_root: PATH
|
||||
-- Document root to look for files or directories
|
||||
once
|
||||
Result := execution_environment.current_working_path.extended ("htdocs")
|
||||
end
|
||||
|
||||
files_root: PATH
|
||||
-- Uploaded files will be stored in `files_root' folder
|
||||
once
|
||||
Result := document_root.extended ("files")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute_not_found (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- `uri' is not found, redirect to default page
|
||||
do
|
||||
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html")
|
||||
end
|
||||
|
||||
execute_upload (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Upload page is requested, either GET or POST
|
||||
-- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images
|
||||
-- On POST display the uploaded files
|
||||
local
|
||||
l_body: STRING_8
|
||||
l_safe_filename: STRING_8
|
||||
fn: PATH
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
n: INTEGER
|
||||
do
|
||||
if req.is_request_method ("GET") or else not req.has_uploaded_file then
|
||||
create page.make
|
||||
page.set_title ("EWF: Upload file")
|
||||
page.add_style (req.script_url ("style.css"), "all")
|
||||
create l_body.make_empty
|
||||
page.set_body (l_body)
|
||||
l_body.append ("<h1>EWF: Upload image file</h1>%N")
|
||||
l_body.append ("<form action=%""+ req.script_url ("/upload") +"%" method=%"POST%" enctype=%"multipart/form-data%">%N")
|
||||
if attached {WSF_STRING} req.query_parameter ("nb") as p_nb and then p_nb.is_integer then
|
||||
n := p_nb.integer_value
|
||||
else
|
||||
n := 1
|
||||
end
|
||||
if attached {WSF_STRING} req.query_parameter ("demo") as p_demo then
|
||||
fn := document_root.extended (p_demo.value)
|
||||
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.name) +"%"></br>%N")
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
n = 0
|
||||
loop
|
||||
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" accept=%"image/*%"></br>%N")
|
||||
n := n - 1
|
||||
end
|
||||
l_body.append (" <input type=%"submit%" value=%"Upload%"/>%N</form>")
|
||||
res.send (page)
|
||||
else
|
||||
create l_body.make (255)
|
||||
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
|
||||
l_body.append ("<ul>")
|
||||
n := 0
|
||||
across
|
||||
req.uploaded_files as c
|
||||
loop
|
||||
n := n + 1
|
||||
l_body.append ("<li>")
|
||||
l_body.append ("<div>" + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "</div>")
|
||||
l_safe_filename := c.item.safe_filename
|
||||
fn := files_root.extended (l_safe_filename)
|
||||
if c.item.move_to (fn.name) then
|
||||
if c.item.content_type.starts_with ("image") then
|
||||
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%"><img src=%"../files/"+ l_safe_filename +"%" /></a>")
|
||||
else
|
||||
l_body.append ("File " + html_encode (c.item.filename) + " is not a supported image<br/>%N")
|
||||
end
|
||||
end
|
||||
l_body.append ("</li>")
|
||||
end
|
||||
|
||||
l_body.append ("</ul>")
|
||||
|
||||
create page.make
|
||||
page.set_title ("EWF: uploaded image")
|
||||
page.add_style ("../style.css", "all")
|
||||
page.set_body (l_body)
|
||||
res.send (page)
|
||||
end
|
||||
end
|
||||
|
||||
execute_upload_put (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Upload page is requested, PUT
|
||||
require
|
||||
is_put_request_method: req.is_put_request_method
|
||||
local
|
||||
l_body: STRING_8
|
||||
l_safe_filename: detachable READABLE_STRING_32
|
||||
fn: PATH
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
n: INTEGER
|
||||
do
|
||||
create l_body.make (255)
|
||||
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
|
||||
l_body.append ("<ul>")
|
||||
n := 0
|
||||
if attached {WSF_STRING} req.path_parameter ("name") as p_name then
|
||||
l_safe_filename := p_name.value
|
||||
end
|
||||
if l_safe_filename = Void or else l_safe_filename.is_empty then
|
||||
l_safe_filename := "input_data"
|
||||
end
|
||||
if n = 0 and req.content_length_value > 0 then
|
||||
if attached new_temporary_output_file ("tmp-uploaded-file_" + n.out) as f then
|
||||
req.read_input_data_into_file (f)
|
||||
f.close
|
||||
fn := files_root.extended (l_safe_filename)
|
||||
f.rename_file (fn.name)
|
||||
l_body.append ("<li>")
|
||||
l_body.append ("<div>Input data : size=" + f.count.out + " (" + req.content_length_value.out + ")</div>")
|
||||
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%">"+ html_encode (l_safe_filename) +"</a>")
|
||||
l_body.append ("</li>")
|
||||
end
|
||||
end
|
||||
l_body.append ("</ul>")
|
||||
|
||||
create page.make
|
||||
page.set_title ("EWF: uploaded image")
|
||||
page.add_style ("../style.css", "all")
|
||||
page.set_body (l_body)
|
||||
res.send (page)
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Encoder
|
||||
|
||||
new_temporary_output_file (n: detachable READABLE_STRING_8): detachable FILE
|
||||
local
|
||||
bp: detachable PATH
|
||||
d: DIRECTORY
|
||||
i: INTEGER
|
||||
do
|
||||
create bp.make_current
|
||||
create d.make_with_path (bp)
|
||||
if not d.exists then
|
||||
d.recursive_create_dir
|
||||
end
|
||||
if n /= Void then
|
||||
bp := bp.extended ("tmp-download-" + n)
|
||||
else
|
||||
bp := bp.extended ("tmp")
|
||||
end
|
||||
from
|
||||
i := 0
|
||||
until
|
||||
Result /= Void or i > 100
|
||||
loop
|
||||
i := i + 1
|
||||
create {RAW_FILE} Result.make_with_path (bp.appended ("__" + i.out))
|
||||
if Result.exists then
|
||||
Result := Void
|
||||
else
|
||||
Result.open_write
|
||||
end
|
||||
end
|
||||
ensure
|
||||
Result /= Void implies Result.is_open_write
|
||||
end
|
||||
|
||||
url_encode (s: READABLE_STRING_32): STRING_8
|
||||
-- URL Encode `s' as Result
|
||||
do
|
||||
Result := url_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
url_encoder: URL_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
html_encode (s: READABLE_STRING_32): STRING_8
|
||||
-- HTML Encode `s' as Result
|
||||
do
|
||||
Result := html_encoder.encoded_string (s)
|
||||
end
|
||||
|
||||
html_encoder: HTML_ENCODER
|
||||
once
|
||||
create Result
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,23 +1,23 @@
|
||||
note
|
||||
description: "[
|
||||
This class represents the value of a HTTP cookie, transferred in a request.
|
||||
The class has features to build an HTTP cookie.
|
||||
|
||||
Following a newer RFC standard for Cookies http://tools.ietf.org/html/rfc6265
|
||||
|
||||
Domain
|
||||
* WARNING: Some existing user agents treat an absent Domain attribute as if the Domain attribute were present and contained the current host name.
|
||||
* For example, if example.com returns a Set-Cookie header without a Domain attribute, these user agents will erroneously send the cookie to www.example.com as well.
|
||||
|
||||
Max-Age, Expires
|
||||
* If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence and controls the expiration date of the cookie.
|
||||
* If a cookie has neither the Max-Age nor the Expires attribute, the user agent will retain the cookie until "the current session is over" (as defined by the user agent).
|
||||
* You will need to call the feature
|
||||
|
||||
HttpOnly, Secure
|
||||
* Note that the HttpOnly attribute is independent of the Secure attribute: a cookie can have both the HttpOnly and the Secure attribute.
|
||||
This class represents the value of a HTTP cookie, transferred in a request.
|
||||
The class has features to build an HTTP cookie.
|
||||
|
||||
Following a newer RFC standard for Cookies http://tools.ietf.org/html/rfc6265
|
||||
|
||||
Domain
|
||||
* WARNING: Some existing user agents treat an absent Domain attribute as if the Domain attribute were present and contained the current host name.
|
||||
* For example, if example.com returns a Set-Cookie header without a Domain attribute, these user agents will erroneously send the cookie to www.example.com as well.
|
||||
|
||||
Max-Age, Expires
|
||||
* If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence and controls the expiration date of the cookie.
|
||||
* If a cookie has neither the Max-Age nor the Expires attribute, the user agent will retain the cookie until "the current session is over" (as defined by the user agent).
|
||||
* You will need to call the feature
|
||||
|
||||
HttpOnly, Secure
|
||||
* Note that the HttpOnly attribute is independent of the Secure attribute: a cookie can have both the HttpOnly and the Secure attribute.
|
||||
|
||||
]"
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
EIS: "name=HTTP Cookie specification", "src=http://tools.ietf.org/html/rfc6265", "protocol=uri"
|
||||
@@ -48,38 +48,38 @@ feature {NONE} -- Initialization
|
||||
feature -- Access
|
||||
|
||||
name: STRING_8
|
||||
-- name of the cookie.
|
||||
-- name of the cookie.
|
||||
|
||||
value: STRING_8
|
||||
-- value of the cookie.
|
||||
-- value of the cookie.
|
||||
|
||||
expiration: detachable STRING_8
|
||||
-- Value of the Expires attribute.
|
||||
-- Value of the Expires attribute.
|
||||
|
||||
path: detachable STRING_8
|
||||
-- Value of the Path attribute.
|
||||
-- Path to which the cookie applies.
|
||||
--| The path "/", specify a cookie that apply to all URLs in your site.
|
||||
-- Value of the Path attribute.
|
||||
-- Path to which the cookie applies.
|
||||
--| The path "/", specify a cookie that apply to all URLs in your site.
|
||||
|
||||
domain: detachable STRING_8
|
||||
-- Value of the Domain attribute.
|
||||
-- Domain to which the cookies apply.
|
||||
-- Value of the Domain attribute.
|
||||
-- Domain to which the cookies apply.
|
||||
|
||||
secure: BOOLEAN
|
||||
-- Value of the Secure attribute.
|
||||
-- By default False.
|
||||
--| Indicate if the cookie should only be sent over secured(encrypted connections, for example SSL).
|
||||
-- Value of the Secure attribute.
|
||||
-- By default False.
|
||||
--| Indicate if the cookie should only be sent over secured(encrypted connections, for example SSL).
|
||||
|
||||
http_only: BOOLEAN
|
||||
-- Value of the http_only attribute.
|
||||
-- By default false.
|
||||
--| Limits the scope of the cookie to HTTP requests.
|
||||
-- Value of the http_only attribute.
|
||||
-- By default false.
|
||||
--| Limits the scope of the cookie to HTTP requests.
|
||||
|
||||
max_age: INTEGER
|
||||
-- Value of the Max-Age attribute.
|
||||
--| How much time in seconds should elapsed before the cookie expires.
|
||||
--| By default max_age < 0 indicate a cookie will last only for the current user-agent (Browser, etc) session.
|
||||
--| A value of 0 instructs the user-agent to delete the cookie.
|
||||
-- Value of the Max-Age attribute.
|
||||
--| How much time in seconds should elapsed before the cookie expires.
|
||||
--| By default max_age < 0 indicate a cookie will last only for the current user-agent (Browser, etc) session.
|
||||
--| A value of 0 instructs the user-agent to delete the cookie.
|
||||
|
||||
has_valid_characters (a_name: READABLE_STRING_8):BOOLEAN
|
||||
-- Has `a_name' valid characters for cookies?
|
||||
@@ -102,12 +102,12 @@ feature -- Access
|
||||
end
|
||||
|
||||
include_max_age: BOOLEAN
|
||||
-- Does the Set-Cookie header include Max-Age attribute?
|
||||
--|By default will include both.
|
||||
-- Does the Set-Cookie header include Max-Age attribute?
|
||||
--|By default will include both.
|
||||
|
||||
include_expires: BOOLEAN
|
||||
-- Does the Set-Cookie header include Expires attribute?
|
||||
--|By default will include both.
|
||||
-- Does the Set-Cookie header include Expires attribute?
|
||||
--|By default will include both.
|
||||
|
||||
|
||||
is_valid_rfc1123_date (a_string: READABLE_STRING_8): BOOLEAN
|
||||
@@ -118,7 +118,7 @@ feature -- Access
|
||||
create d.make_from_string (a_string)
|
||||
Result := not d.has_error and then d.rfc1123_string.same_string (a_string)
|
||||
end
|
||||
|
||||
|
||||
feature -- Change Element
|
||||
|
||||
set_name (a_name: READABLE_STRING_8)
|
||||
@@ -323,20 +323,20 @@ feature {NONE} -- Constants
|
||||
-- 0x2D-3A: -./0123456789:
|
||||
-- 0x3C-5B: <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[
|
||||
-- 0x5D-7E: ]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
||||
note
|
||||
EIS: "name=valid-characters", "src=http://tools.ietf.org/html/rfc6265#section-4.1.1", "protocol=uri"
|
||||
do
|
||||
Result := True
|
||||
inspect c
|
||||
when 0x21 then
|
||||
when 0x23 .. 0x2B then
|
||||
when 0x2D .. 0x3A then
|
||||
when 0x3C .. 0x5B then
|
||||
when 0x5D .. 0x7E then
|
||||
else
|
||||
Result := False
|
||||
end
|
||||
note
|
||||
EIS: "name=valid-characters", "src=http://tools.ietf.org/html/rfc6265#section-4.1.1", "protocol=uri"
|
||||
do
|
||||
Result := True
|
||||
inspect c
|
||||
when 0x21 then
|
||||
when 0x23 .. 0x2B then
|
||||
when 0x2D .. 0x3A then
|
||||
when 0x3C .. 0x5B then
|
||||
when 0x5D .. 0x7E then
|
||||
else
|
||||
Result := False
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_DATE_TIME_UTILITIES}."
|
||||
description: "[
|
||||
Utilities routines to manipulate date
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_FORMAT_CONSTANTS}."
|
||||
description: "Various constants implied in http format."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
note
|
||||
description: "Summary description for {HTTP_REQUEST_METHOD_CONSTANTS}."
|
||||
description: "[
|
||||
Constants related to HTTP request method identification
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
note
|
||||
description: "Summary description for {NOTIFICATION_CHAIN_MAILER}."
|
||||
author: ""
|
||||
description: "[
|
||||
Node of a notification mailer chain
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -7,18 +7,8 @@ class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SKELETON_SERVICE
|
||||
undefine
|
||||
requires_proxy
|
||||
end
|
||||
|
||||
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
|
||||
|
||||
WSF_SERVICE
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
ANY
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
@@ -31,15 +21,13 @@ feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
local
|
||||
launcher: WSF_NINO_SERVICE_LAUNCHER
|
||||
launcher: WSF_NINO_SERVICE_LAUNCHER [APPLICATION_EXECUTION]
|
||||
opts: WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
do
|
||||
initialize_router
|
||||
|
||||
create opts.make
|
||||
opts.set_verbose (True)
|
||||
opts.set_option ("port", 0)
|
||||
create launcher.make (Current, opts)
|
||||
create launcher.make (opts)
|
||||
launcher.on_launched_actions.extend (agent on_launched)
|
||||
launcher.launch
|
||||
end
|
||||
@@ -49,7 +37,7 @@ feature {NONE} -- Initialization
|
||||
e: EXECUTION_ENVIRONMENT
|
||||
cmd: STRING_32
|
||||
do
|
||||
if attached {WGI_NINO_CONNECTOR} conn as nino then
|
||||
if attached {WGI_NINO_CONNECTOR [APPLICATION_EXECUTION]} conn as nino then
|
||||
e := execution_environment
|
||||
create cmd.make (32)
|
||||
if attached e.item ("COMSPEC") as l_comspec then
|
||||
@@ -64,105 +52,4 @@ feature {NONE} -- Initialization
|
||||
end
|
||||
end
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_uri_template_agent ("/", agent handle_root)
|
||||
map_uri_template_agent ("/openid", agent handle_openid)
|
||||
end
|
||||
|
||||
handle_root (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
s: STRING
|
||||
do
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
create s.make_empty
|
||||
s.append ("<form action=%"" + req.script_url ("/openid") + "%" method=%"POST%">%N")
|
||||
s.append ("<strong>OpenID identifier</strong> <input type='text' name='openid_identifier' value='' size='60'/>")
|
||||
s.append ("<input type='submit' name='op' value='sign with OpenID' />")
|
||||
s.append ("</form>%N")
|
||||
s.append ("<form action=%"" + req.script_url ("/openid") + "%" method=%"POST%">%N")
|
||||
s.append ("<strong>OpenID identifier</strong> <input type='text' name='openid_identifier' value='https://www.google.com/accounts/o8/id' size='60'/>")
|
||||
s.append ("<input type='submit' name='op' value='sign with Google' />")
|
||||
s.append ("</form>%N")
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
end
|
||||
|
||||
handle_openid (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE
|
||||
s: STRING
|
||||
o: OPENID_CONSUMER
|
||||
v: OPENID_CONSUMER_VALIDATION
|
||||
do
|
||||
if attached req.string_item ("openid.mode") as l_openid_mode then
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
create s.make_empty
|
||||
|
||||
if l_openid_mode.same_string ("id_res") then
|
||||
o := new_openid_consumer (req)
|
||||
create v.make_from_items (o, req.items_as_string_items)
|
||||
v.validate
|
||||
if v.is_valid then
|
||||
s.append ("<div>User authenticated</div>")
|
||||
s.append ("<ul>Request items")
|
||||
across
|
||||
req.items as c
|
||||
loop
|
||||
s.append ("<li>" + c.item.url_encoded_name + "=" + c.item.string_representation + "</li>")
|
||||
end
|
||||
s.append ("</ul>")
|
||||
s.append ("<ul>Attributes")
|
||||
across
|
||||
v.attributes as c
|
||||
loop
|
||||
s.append ("<li>" + c.key + "=" + c.item + "</li>")
|
||||
end
|
||||
s.append ("</ul>")
|
||||
else
|
||||
s.append ("<div>User authentication failed!!!</div>")
|
||||
end
|
||||
else
|
||||
s.append ("<div>Unexpected OpenID.mode=" + l_openid_mode + "</div>")
|
||||
end
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
elseif attached req.string_item ("openid_identifier") as l_id then
|
||||
create s.make_empty
|
||||
|
||||
o := new_openid_consumer (req)
|
||||
s.append ("Testing " + l_id + "<br>%N")
|
||||
s.append ("Return-to" + o.return_url + "<br>")
|
||||
if attached o.auth_url (l_id) as l_auth_url then
|
||||
s.append ("<a href=%""+ l_auth_url + "%">Click to sign with " + l_id + "</a><br>")
|
||||
create redir.make (l_auth_url, 1)
|
||||
s.append ("Automatically follow link in " + redir.delay.out + " second(s)<br>")
|
||||
redir.set_title ("EWF::OpenID demo")
|
||||
redir.set_body (s)
|
||||
res.send (redir)
|
||||
else
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
end
|
||||
else
|
||||
res.redirect_now ("/")
|
||||
end
|
||||
end
|
||||
|
||||
new_openid_consumer (req: WSF_REQUEST): OPENID_CONSUMER
|
||||
do
|
||||
create Result.make (req.absolute_script_url ("/openid"))
|
||||
|
||||
Result.ask_email (True)
|
||||
Result.ask_all_info (False)
|
||||
-- Result.ask_nickname (False)
|
||||
-- Result.ask_fullname (False)
|
||||
-- Result.ask_country (True)
|
||||
end
|
||||
end
|
||||
|
||||
131
library/security/openid/consumer/demo/application_execution.e
Normal file
131
library/security/openid/consumer/demo/application_execution.e
Normal file
@@ -0,0 +1,131 @@
|
||||
note
|
||||
description : "OPENID demo application root class"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
APPLICATION_EXECUTION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_SKELETON_EXECUTION
|
||||
undefine
|
||||
requires_proxy
|
||||
end
|
||||
|
||||
WSF_ROUTED_URI_TEMPLATE_HELPER
|
||||
|
||||
WSF_NO_PROXY_POLICY
|
||||
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
do
|
||||
map_uri_template_agent ("/", agent handle_root)
|
||||
map_uri_template_agent ("/openid", agent handle_openid)
|
||||
end
|
||||
|
||||
handle_root (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
s: STRING
|
||||
do
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
create s.make_empty
|
||||
s.append ("<form action=%"" + req.script_url ("/openid") + "%" method=%"POST%">%N")
|
||||
s.append ("<strong>OpenID identifier</strong> <input type='text' name='openid_identifier' value='' size='60'/>")
|
||||
s.append ("<input type='submit' name='op' value='sign with OpenID' />")
|
||||
s.append ("</form>%N")
|
||||
s.append ("<form action=%"" + req.script_url ("/openid") + "%" method=%"POST%">%N")
|
||||
s.append ("<strong>OpenID identifier</strong> <input type='text' name='openid_identifier' value='https://www.google.com/accounts/o8/id' size='60'/>")
|
||||
s.append ("<input type='submit' name='op' value='sign with Google' />")
|
||||
s.append ("</form>%N")
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
end
|
||||
|
||||
handle_openid (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE
|
||||
s: STRING
|
||||
o: OPENID_CONSUMER
|
||||
v: OPENID_CONSUMER_VALIDATION
|
||||
do
|
||||
if attached req.string_item ("openid.mode") as l_openid_mode then
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
create s.make_empty
|
||||
|
||||
if l_openid_mode.same_string ("id_res") then
|
||||
o := new_openid_consumer (req)
|
||||
create v.make_from_items (o, req.items_as_string_items)
|
||||
v.validate
|
||||
if v.is_valid then
|
||||
s.append ("<div>User authenticated</div>")
|
||||
s.append ("<ul>Request items")
|
||||
across
|
||||
req.items as c
|
||||
loop
|
||||
s.append ("<li>" + c.item.url_encoded_name + "=" + c.item.string_representation + "</li>")
|
||||
end
|
||||
s.append ("</ul>")
|
||||
s.append ("<ul>Attributes")
|
||||
across
|
||||
v.attributes as c
|
||||
loop
|
||||
s.append ("<li>" + c.key + "=" + c.item + "</li>")
|
||||
end
|
||||
s.append ("</ul>")
|
||||
else
|
||||
s.append ("<div>User authentication failed!!!</div>")
|
||||
end
|
||||
else
|
||||
s.append ("<div>Unexpected OpenID.mode=" + l_openid_mode + "</div>")
|
||||
end
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
elseif attached req.string_item ("openid_identifier") as l_id then
|
||||
create s.make_empty
|
||||
|
||||
o := new_openid_consumer (req)
|
||||
s.append ("Testing " + l_id + "<br>%N")
|
||||
s.append ("Return-to" + o.return_url + "<br>")
|
||||
if attached o.auth_url (l_id) as l_auth_url then
|
||||
s.append ("<a href=%""+ l_auth_url + "%">Click to sign with " + l_id + "</a><br>")
|
||||
create redir.make (l_auth_url, 1)
|
||||
s.append ("Automatically follow link in " + redir.delay.out + " second(s)<br>")
|
||||
redir.set_title ("EWF::OpenID demo")
|
||||
redir.set_body (s)
|
||||
res.send (redir)
|
||||
else
|
||||
create m.make
|
||||
m.set_title ("EWF::OpenID demo")
|
||||
m.set_body (s)
|
||||
res.send (m)
|
||||
end
|
||||
else
|
||||
res.redirect_now ("/")
|
||||
end
|
||||
end
|
||||
|
||||
new_openid_consumer (req: WSF_REQUEST): OPENID_CONSUMER
|
||||
do
|
||||
create Result.make (req.absolute_script_url ("/openid"))
|
||||
|
||||
Result.ask_email (True)
|
||||
Result.ask_all_info (False)
|
||||
-- Result.ask_nickname (False)
|
||||
-- Result.ask_fullname (False)
|
||||
-- Result.ask_country (True)
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="connector_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||
<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_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||
<target name="connector_cgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -12,6 +12,7 @@
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="http" location="../../../../network/protocol/http/http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
note
|
||||
description: "Summary description for {WGI_CGI_CONNECTOR}."
|
||||
description: "CGI connector, see CGI interface, and CGI scripts."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WGI_CGI_CONNECTOR
|
||||
WGI_CGI_CONNECTOR [G -> WGI_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
WGI_CONNECTOR
|
||||
|
||||
create
|
||||
make
|
||||
SHARED_HTML_ENCODER
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_service: like service)
|
||||
do
|
||||
service := a_service
|
||||
end
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
feature -- Access
|
||||
|
||||
@@ -27,37 +21,27 @@ feature -- Access
|
||||
Version: STRING_8 = "0.1"
|
||||
-- Version of Current connector
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
service: WGI_SERVICE
|
||||
-- Gateway Service
|
||||
|
||||
feature -- Execution
|
||||
|
||||
launch
|
||||
-- Launch execution of CGI application.
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM
|
||||
exec: detachable WGI_EXECUTION
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
create req.make ((create {EXECUTION_ENVIRONMENT}).starting_environment, create {WGI_CGI_INPUT_STREAM}.make, Current)
|
||||
create req.make (execution_environment.starting_environment, create {WGI_CGI_INPUT_STREAM}.make, Current)
|
||||
create res.make (create {WGI_CGI_OUTPUT_STREAM}.make, create {WGI_CGI_ERROR_STREAM}.make)
|
||||
service.execute (req, res)
|
||||
create {G} exec.make (req, res)
|
||||
exec.execute
|
||||
res.push
|
||||
exec.clean
|
||||
else
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (l_trace)
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
process_rescue (res)
|
||||
if exec /= Void then
|
||||
exec.clean
|
||||
end
|
||||
end
|
||||
rescue
|
||||
@@ -67,6 +51,24 @@ feature -- Execution
|
||||
end
|
||||
end
|
||||
|
||||
process_rescue (res: detachable WGI_RESPONSE)
|
||||
-- Handle rescued execution of current request.
|
||||
do
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (html_encoder.encoded_string (l_trace))
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_CGI_ERROR_STREAM."
|
||||
description: "Error stream for CGI connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_CGI_INPUT_STREAM."
|
||||
description: "Input stream for CGI connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_CGI_OUTPUT_STREAM."
|
||||
description: "Output stream for CGI connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
@@ -70,8 +70,13 @@ feature -- Status writing
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_available: BOOLEAN = True
|
||||
-- <Precursor>
|
||||
|
||||
note
|
||||
copyright: "2011-2011, 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_libfcgi" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi">
|
||||
<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_libfcgi" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi">
|
||||
<target name="connector_libfcgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -13,6 +13,7 @@
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf"/>
|
||||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi.ecf" />
|
||||
<library name="http" location="../../../../network/protocol/http/http.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
note
|
||||
description: "Summary description for {WGI_LIBFCGI_CONNECTOR}."
|
||||
description: "libFCGI connector, see libfcgi and http://fastcgi.com"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WGI_LIBFCGI_CONNECTOR
|
||||
WGI_LIBFCGI_CONNECTOR [G -> WGI_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
WGI_CONNECTOR
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
SHARED_HTML_ENCODER
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_service: like service)
|
||||
default_create
|
||||
-- Create libFCGI connector.
|
||||
do
|
||||
service := a_service
|
||||
Precursor {WGI_CONNECTOR}
|
||||
create fcgi.make
|
||||
create input.make (fcgi)
|
||||
create output.make (fcgi)
|
||||
@@ -32,14 +38,10 @@ feature -- Access
|
||||
Version: STRING_8 = "0.1"
|
||||
-- Version of Current connector
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
service: WGI_SERVICE
|
||||
-- Gateway Service
|
||||
|
||||
feature -- Server
|
||||
|
||||
launch
|
||||
-- Launch libFCGI server.
|
||||
local
|
||||
res: INTEGER
|
||||
do
|
||||
@@ -56,30 +58,25 @@ feature -- Server
|
||||
feature -- Execution
|
||||
|
||||
process_fcgi_request (vars: STRING_TABLE [READABLE_STRING_8]; a_input: like input; a_output: like output)
|
||||
-- Process the request with variables `vars', input `a_input' and output `a_output'.
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_RESPONSE_STREAM
|
||||
exec: detachable WGI_EXECUTION
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
a_input.reset
|
||||
create req.make (vars, a_input, Current)
|
||||
create res.make (a_output, a_output)
|
||||
service.execute (req, res)
|
||||
create {G} exec.make (req, res)
|
||||
exec.execute
|
||||
res.push
|
||||
exec.clean
|
||||
else
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (l_trace)
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
process_rescue (res)
|
||||
if exec /= Void then
|
||||
exec.clean
|
||||
end
|
||||
end
|
||||
rescue
|
||||
@@ -89,6 +86,24 @@ feature -- Execution
|
||||
end
|
||||
end
|
||||
|
||||
process_rescue (res: detachable WGI_RESPONSE)
|
||||
-- Handle rescued execution of current request.
|
||||
do
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (html_encoder.encoded_string (l_trace))
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Input/Output
|
||||
|
||||
input: WGI_LIBFCGI_INPUT_STREAM
|
||||
@@ -105,7 +120,7 @@ invariant
|
||||
fcgi_attached: fcgi /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2013, 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_LIBFCGI_INPUT_STREAM."
|
||||
description: "Input stream for libFCGI connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {WGI_LIBFCGI_OUTPUT_STREAM}."
|
||||
description: "Output stream for libFCGI connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
@@ -38,6 +38,11 @@ feature -- Status report
|
||||
Result := True
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_available: BOOLEAN = True
|
||||
-- <Precursor>
|
||||
|
||||
feature -- Status writing
|
||||
|
||||
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
|
||||
@@ -100,7 +105,7 @@ invariant
|
||||
fcgi_attached: fcgi /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2011, 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
|
||||
|
||||
@@ -4,50 +4,31 @@ note
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NINO_SERVICE
|
||||
NINO_SERVICE [G -> WGI_EXECUTION create make end]
|
||||
|
||||
create
|
||||
make,
|
||||
make_custom,
|
||||
make_with_callback,
|
||||
make_custom_with_callback
|
||||
make_custom
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
make (a_service: WGI_SERVICE)
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
make_custom (a_service, Void)
|
||||
make_custom (Void)
|
||||
end
|
||||
|
||||
make_custom (a_service: WGI_SERVICE; a_base_url: detachable STRING)
|
||||
make_custom (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 ("/")
|
||||
do
|
||||
create connector.make_with_base (a_service, 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)
|
||||
create connector.make_with_base (a_base_url)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
connector: WGI_NINO_CONNECTOR
|
||||
connector: WGI_NINO_CONNECTOR [G]
|
||||
-- Web server connector
|
||||
|
||||
feature -- Status report
|
||||
@@ -104,7 +85,7 @@ feature -- Server
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, 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,26 +1,26 @@
|
||||
note
|
||||
description: "Summary description for {WGI_NINO_CONNECTOR}."
|
||||
description: "Standalone Eiffel Web nino server connector."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WGI_NINO_CONNECTOR
|
||||
WGI_NINO_CONNECTOR [G -> WGI_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
WGI_CONNECTOR
|
||||
|
||||
SHARED_HTML_ENCODER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_base
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_service: like service)
|
||||
make
|
||||
local
|
||||
cfg: HTTP_SERVER_CONFIGURATION
|
||||
do
|
||||
service := a_service
|
||||
|
||||
create cfg.make
|
||||
create server.make (cfg)
|
||||
|
||||
@@ -29,11 +29,11 @@ feature {NONE} -- Initialization
|
||||
create on_stopped_actions
|
||||
end
|
||||
|
||||
make_with_base (a_service: like service; a_base: like base)
|
||||
make_with_base (a_base: like base)
|
||||
require
|
||||
a_base_starts_with_slash: (a_base /= Void and then not a_base.is_empty) implies a_base.starts_with ("/")
|
||||
do
|
||||
make (a_service)
|
||||
make -- (a_service)
|
||||
set_base (a_base)
|
||||
end
|
||||
|
||||
@@ -45,11 +45,6 @@ feature -- Access
|
||||
version: STRING_8 = "0.1"
|
||||
-- Version of Current connector
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
service: WGI_SERVICE
|
||||
-- Gateway Service
|
||||
|
||||
feature -- Access
|
||||
|
||||
server: HTTP_SERVER
|
||||
@@ -118,7 +113,7 @@ feature -- Server
|
||||
do
|
||||
launched := False
|
||||
port := 0
|
||||
create {WGI_NINO_HANDLER} l_http_handler.make_with_callback (server, Current)
|
||||
create {WGI_NINO_HANDLER [G]} l_http_handler.make_with_callback (server, Current)
|
||||
if configuration.is_verbose then
|
||||
if attached base as l_base then
|
||||
io.error.put_string ("Base=" + l_base + "%N")
|
||||
@@ -128,17 +123,27 @@ feature -- Server
|
||||
end
|
||||
|
||||
process_request (env: STRING_TABLE [READABLE_STRING_8]; a_headers_text: STRING; a_socket: TCP_STREAM_SOCKET)
|
||||
-- Process request ...
|
||||
local
|
||||
req: WGI_REQUEST_FROM_TABLE
|
||||
res: detachable WGI_NINO_RESPONSE_STREAM
|
||||
exec: detachable WGI_EXECUTION
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
create req.make (env, create {WGI_NINO_INPUT_STREAM}.make (a_socket), Current)
|
||||
create res.make (create {WGI_NINO_OUTPUT_STREAM}.make (a_socket), create {WGI_NINO_ERROR_STREAM}.make_stderr (a_socket.descriptor.out))
|
||||
req.set_meta_string_variable ("RAW_HEADER_DATA", a_headers_text)
|
||||
service.execute (req, res)
|
||||
|
||||
create {G} exec.make (req, res)
|
||||
exec.execute
|
||||
res.push
|
||||
exec.clean
|
||||
else
|
||||
process_rescue (res)
|
||||
if exec /= Void then
|
||||
exec.clean
|
||||
end
|
||||
end
|
||||
rescue
|
||||
if not retried then
|
||||
@@ -147,8 +152,25 @@ feature -- Server
|
||||
end
|
||||
end
|
||||
|
||||
process_rescue (res: detachable WGI_RESPONSE)
|
||||
do
|
||||
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.trace as l_trace then
|
||||
if res /= Void then
|
||||
if not res.status_is_set then
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
|
||||
end
|
||||
if res.message_writable then
|
||||
res.put_string ("<pre>")
|
||||
res.put_string (html_encoder.encoded_string (l_trace))
|
||||
res.put_string ("</pre>")
|
||||
end
|
||||
res.push
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_CGI_ERROR_STREAM."
|
||||
description: "Error stream for Nino connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -5,7 +5,7 @@ note
|
||||
revision : "$Revision$"
|
||||
|
||||
class
|
||||
WGI_NINO_HANDLER
|
||||
WGI_NINO_HANDLER [G -> WGI_EXECUTION create make end]
|
||||
|
||||
inherit
|
||||
HTTP_CONNECTION_HANDLER
|
||||
@@ -27,7 +27,7 @@ feature {NONE} -- Initialization
|
||||
callback := a_callback
|
||||
end
|
||||
|
||||
callback: WGI_NINO_CONNECTOR
|
||||
callback: WGI_NINO_CONNECTOR [G]
|
||||
|
||||
feature -- Access
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {WGI_NINO_INPUT_STREAM}."
|
||||
description: "Input stream for Nino connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {WGI_NINO_OUTPUT_STREAM}."
|
||||
description: "Output stream for Nino connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
@@ -79,6 +79,15 @@ feature -- Status report
|
||||
Result := target.is_open_write
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_available: BOOLEAN
|
||||
-- <Precursor>
|
||||
-- FIXME: see how "standalone" connection is doing that.
|
||||
do
|
||||
Result := target.is_open_read
|
||||
end
|
||||
|
||||
feature -- Basic operations
|
||||
|
||||
flush
|
||||
@@ -86,7 +95,7 @@ feature -- Basic operations
|
||||
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,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for {WGI_NULL_CONNECTOR}."
|
||||
description: "NULL connector, mainly used for void-safety purpose or testing"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_NULL_FILE_INPUT_STREAM."
|
||||
description: "Null Input stream based on FILE."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_NULL_INPUT_STREAM."
|
||||
description: "Input stream for NULL connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_NULL_OUTPUT_STREAM."
|
||||
description: "Output stream for NULL connector."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
@@ -70,8 +70,13 @@ feature -- Status writing
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_available: BOOLEAN = True
|
||||
-- <Precursor>
|
||||
|
||||
note
|
||||
copyright: "2011-2011, 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
note
|
||||
description: "Summary description for WGI_NULL_STRING_INPUT_STREAM."
|
||||
description: "Input stream for NULL connector based on string body (in memory)."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
|
||||
10
library/server/ewsgi/connectors/standalone/license.lic
Normal file
10
library/server/ewsgi/connectors/standalone/license.lic
Normal file
@@ -0,0 +1,10 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, 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
|
||||
]"
|
||||
@@ -0,0 +1,86 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: none
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
do
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- <Precursor>
|
||||
|
||||
shutdown_requested (a_server: like server): BOOLEAN
|
||||
do
|
||||
-- FIXME: we should probably remove this possibility, check with EWF if this is needed.
|
||||
Result := a_server.controller.shutdown_requested
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: HTTPD_STREAM_SOCKET
|
||||
do
|
||||
is_shutdown_requested := is_shutdown_requested or shutdown_requested (server)
|
||||
if is_shutdown_requested then
|
||||
-- Cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
h.safe_execute
|
||||
end
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
update_is_shutdown_requested
|
||||
end
|
||||
|
||||
update_is_shutdown_requested
|
||||
do
|
||||
is_shutdown_requested := shutdown_requested (server)
|
||||
end
|
||||
|
||||
shutdown
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
server.controller.shutdown
|
||||
end
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown
|
||||
do
|
||||
-- no concurrency, then current task should be done.
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
note
|
||||
description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: none"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: SCOOP
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
local
|
||||
n: INTEGER
|
||||
p: like pool
|
||||
do
|
||||
n := max_concurrent_connections (server)
|
||||
create p.make (n)
|
||||
initialize_pool (p, n)
|
||||
pool := p
|
||||
end
|
||||
|
||||
initialize_pool (p: like pool; n: INTEGER)
|
||||
-- Initialize Concurrent pool of `n' potential separate connection handlers.
|
||||
do
|
||||
p.set_count (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
-- <Precursor>
|
||||
|
||||
max_concurrent_connections (a_server: like server): INTEGER
|
||||
-- Max concurrent connection settings from server `a_server'.
|
||||
do
|
||||
Result := a_server.configuration.max_concurrent_connections
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
shutdown
|
||||
-- <Precursor>
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
pool_gracefull_stop (pool)
|
||||
end
|
||||
end
|
||||
|
||||
pool_gracefull_stop (p: like pool)
|
||||
-- Graceful stop concurrent pool of separate connection handlers.
|
||||
do
|
||||
p.gracefull_stop
|
||||
end
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- <Precursor>
|
||||
do
|
||||
accept_connection_on_pool (pool, a_listening_socket) -- Wait on not pool.is_full or is_stop_requested
|
||||
end
|
||||
|
||||
accept_connection_on_pool (a_pool: like pool; a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
-- Process accept connection
|
||||
-- note that the precondition matters for scoop synchronization.
|
||||
require
|
||||
concurrency: not a_pool.is_full or is_shutdown_requested or a_pool.stop_requested
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection_on_pool")
|
||||
end
|
||||
if is_shutdown_requested then
|
||||
-- Cancel
|
||||
elseif attached a_pool.separate_item (factory) as h then
|
||||
cl := separate_client_socket (h)
|
||||
a_listening_socket.accept_to (cl)
|
||||
process_handler (h)
|
||||
else
|
||||
check is_not_full: False end
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_connection_on_pool")
|
||||
end
|
||||
end
|
||||
|
||||
process_handler (hdl: separate HTTPD_REQUEST_HANDLER)
|
||||
-- Process request handler `hdl' as soon as `hdl' is connected to accepted socket.
|
||||
require
|
||||
hdl.is_connected
|
||||
do
|
||||
hdl.safe_execute
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown.
|
||||
do
|
||||
wait_for_pool_completion (pool)
|
||||
end
|
||||
|
||||
wait_for_pool_completion (p: like pool)
|
||||
-- Wait until concurrent pool is empty and terminated.
|
||||
require
|
||||
p.is_empty -- SCOOP wait condition.
|
||||
do
|
||||
p.terminate
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
separate_client_socket (hdl: separate HTTPD_REQUEST_HANDLER): separate HTTPD_STREAM_SOCKET
|
||||
-- Client socket for request handler `hdl'.
|
||||
do
|
||||
Result := hdl.client_socket
|
||||
end
|
||||
|
||||
pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER]
|
||||
-- Pool of separate connection handlers.
|
||||
|
||||
invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
note
|
||||
description: "[
|
||||
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
|
||||
and extract information on the request and the server
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
release
|
||||
end
|
||||
|
||||
CONCURRENT_POOL_ITEM
|
||||
rename
|
||||
release as release_pool_item
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- <Precursor>
|
||||
local
|
||||
d: STRING
|
||||
do
|
||||
if attached internal_client_socket as l_socket then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
release_pool_item
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
end
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: SCOOP"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
CONCURRENT_POOL_FACTORY [HTTPD_REQUEST_HANDLER]
|
||||
rename
|
||||
new_separate_item as new_handler
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,190 @@
|
||||
note
|
||||
description: "Concurrent pool for SCOOP concurrency mode."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
CONCURRENT_POOL [G -> CONCURRENT_POOL_ITEM]
|
||||
|
||||
inherit
|
||||
HTTPD_DEBUG_FACILITIES
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (n: INTEGER)
|
||||
do
|
||||
capacity := n
|
||||
create items.make_empty (n)
|
||||
create busy_items.make_empty (n)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
count: INTEGER
|
||||
-- Number of concurrent items managed by Current pool.
|
||||
|
||||
capacity: INTEGER
|
||||
-- Maximum number of concurrent items managed by Current pool.
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_full: BOOLEAN
|
||||
-- Pool is full?
|
||||
do
|
||||
Result := count >= capacity
|
||||
end
|
||||
|
||||
is_empty: BOOLEAN
|
||||
-- No concurrent item waiting in current pool.
|
||||
do
|
||||
Result := count = 0
|
||||
end
|
||||
|
||||
stop_requested: BOOLEAN
|
||||
-- Current pool received a request to terminate.
|
||||
|
||||
feature -- Access
|
||||
|
||||
separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G
|
||||
-- Reused, or new separate item of type {G} created by `a_factory'.
|
||||
require
|
||||
is_not_full: not is_full
|
||||
local
|
||||
i,n,pos: INTEGER
|
||||
lst: like busy_items
|
||||
l_item: detachable separate G
|
||||
do
|
||||
if not stop_requested then
|
||||
from
|
||||
lst := busy_items
|
||||
pos := -1
|
||||
i := 0
|
||||
n := lst.count - 1
|
||||
until
|
||||
i > n or l_item /= Void or pos >= 0
|
||||
loop
|
||||
if not lst [i] then -- is free (i.e not busy)
|
||||
pos := i
|
||||
|
||||
if items.valid_index (pos) then
|
||||
l_item := items [pos]
|
||||
if l_item /= Void then
|
||||
busy_items [pos] := True
|
||||
end
|
||||
end
|
||||
if l_item = Void then
|
||||
-- Empty, then let's create one.
|
||||
l_item := a_factory.new_separate_item
|
||||
register_item (l_item)
|
||||
items [pos] := l_item
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
if l_item = Void then
|
||||
-- Pool is FULL ...
|
||||
check overcapacity: False end
|
||||
else
|
||||
debug ("pool", "dbglog")
|
||||
dbglog ("Lock pool item #" + pos.out + " (free:"+ (capacity - count).out +"))")
|
||||
end
|
||||
count := count + 1
|
||||
busy_items [pos] := True
|
||||
Result := l_item
|
||||
a_factory.update_item (l_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
gracefull_stop
|
||||
-- Request the Current pool to terminate.
|
||||
do
|
||||
stop_requested := True
|
||||
end
|
||||
|
||||
feature {NONE} -- Internal
|
||||
|
||||
items: SPECIAL [detachable separate G]
|
||||
-- List of concurrent items.
|
||||
|
||||
busy_items: SPECIAL [BOOLEAN]
|
||||
-- Map of items being proceed.
|
||||
|
||||
feature {CONCURRENT_POOL_ITEM} -- Change
|
||||
|
||||
release_item (a_item: separate G)
|
||||
-- Unregister `a_item' from Current pool.
|
||||
require
|
||||
count > 0
|
||||
local
|
||||
i,n,pos: INTEGER
|
||||
lst: like items
|
||||
do
|
||||
-- release handler for reuse
|
||||
from
|
||||
lst := items
|
||||
i := 0
|
||||
n := lst.count - 1
|
||||
until
|
||||
i > n or lst [i] = a_item
|
||||
loop
|
||||
i := i + 1
|
||||
end
|
||||
if i <= n then
|
||||
pos := i
|
||||
busy_items [pos] := False
|
||||
count := count - 1
|
||||
--reuse items [pos] := Void
|
||||
debug ("pool", "dbglog")
|
||||
dbglog ("Released pool item #" + i.out + " (free:"+ (capacity - count).out +"))")
|
||||
end
|
||||
else
|
||||
check known_item: False end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_count (n: INTEGER)
|
||||
-- Set capacity of Current pool to `n'.
|
||||
local
|
||||
g: detachable separate G
|
||||
do
|
||||
capacity := n
|
||||
items.fill_with (g, 0, n - 1)
|
||||
busy_items.fill_with (False, 0, n - 1)
|
||||
end
|
||||
|
||||
terminate
|
||||
-- Terminate current pool.
|
||||
local
|
||||
l_items: like items
|
||||
do
|
||||
l_items := items
|
||||
l_items.wipe_out
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
register_item (a_item: separate G)
|
||||
-- Adopt `a_item' in current pool.
|
||||
do
|
||||
a_item.set_pool (Current)
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
note
|
||||
description: "Factory in charge of creating new concurrent pool item."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM]
|
||||
|
||||
feature -- Access
|
||||
|
||||
update_item (a_item: separate G)
|
||||
-- Update `a_item' for optionally purpose.
|
||||
do
|
||||
end
|
||||
|
||||
new_separate_item: separate G
|
||||
-- New separated object of type {G}.
|
||||
deferred
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
note
|
||||
description: "[
|
||||
Item create by the CONCURRENT_POOL_FACTORY, and managed by the CONCURRENT_POOL
|
||||
for SCOOP concurrency mode.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
CONCURRENT_POOL_ITEM
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]
|
||||
-- Associated concurrent pool component.
|
||||
|
||||
feature {CONCURRENT_POOL} -- Change
|
||||
|
||||
set_pool (p: like pool)
|
||||
-- Set associated `pool' to `p'.
|
||||
do
|
||||
pool := p
|
||||
end
|
||||
|
||||
feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
-- Release Current pool item from associated pool.
|
||||
do
|
||||
if attached pool as p then
|
||||
pool_release (p)
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM])
|
||||
do
|
||||
p.release_item (Current)
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,103 @@
|
||||
note
|
||||
description: "[
|
||||
Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: Thread
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTTPD_CONNECTION_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_CONNECTION_HANDLER_I
|
||||
redefine
|
||||
initialize
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
initialize
|
||||
local
|
||||
n: INTEGER
|
||||
do
|
||||
n := max_concurrent_connections (server)
|
||||
create pool.make (n.to_natural_32)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
is_shutdown_requested: BOOLEAN
|
||||
|
||||
max_concurrent_connections (a_server: like server): INTEGER
|
||||
do
|
||||
Result := a_server.configuration.max_concurrent_connections
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Execution
|
||||
|
||||
shutdown
|
||||
do
|
||||
if not is_shutdown_requested then
|
||||
is_shutdown_requested := True
|
||||
pool_gracefull_stop (pool)
|
||||
end
|
||||
end
|
||||
|
||||
pool_gracefull_stop (p: like pool)
|
||||
do
|
||||
p.terminate
|
||||
end
|
||||
|
||||
accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET)
|
||||
local
|
||||
cl: separate HTTPD_STREAM_SOCKET
|
||||
do
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".ENTER accept_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
|
||||
if is_shutdown_requested then
|
||||
-- cancel
|
||||
elseif attached factory.new_handler as h then
|
||||
cl := h.client_socket
|
||||
a_listening_socket.accept_to (cl)
|
||||
if h.is_connected then
|
||||
pool.add_work (agent h.safe_execute)
|
||||
end
|
||||
end
|
||||
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_socket.descriptor.out +"}")
|
||||
end
|
||||
end
|
||||
|
||||
feature {HTTPD_SERVER_I} -- Status report
|
||||
|
||||
wait_for_completion
|
||||
-- Wait until Current is ready for shutdown
|
||||
do
|
||||
pool.wait_for_completion
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
pool: THREAD_POOL [HTTPD_REQUEST_HANDLER] --ANY] --POOLED_THREAD [HTTP_REQUEST_HANDLER]]
|
||||
-- Pool of concurrent connection handlers.
|
||||
|
||||
invariant
|
||||
pool_attached: pool /= Void
|
||||
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
note
|
||||
description: "[
|
||||
Instance of HTTPD_REQUEST_HANDLER will process the incoming connection
|
||||
and extract information on the request and the server
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_I
|
||||
redefine
|
||||
release
|
||||
end
|
||||
|
||||
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||
|
||||
release
|
||||
local
|
||||
d: STRING
|
||||
do
|
||||
-- FIXME: for log purpose
|
||||
if attached internal_client_socket as l_socket then
|
||||
d := l_socket.descriptor.out
|
||||
else
|
||||
d := "N/A"
|
||||
end
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||
end
|
||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||
debug ("dbglog")
|
||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||
end
|
||||
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)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "Implementation of request handler factory for concurrency mode: Thread"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTPD_REQUEST_HANDLER_FACTORY
|
||||
|
||||
inherit
|
||||
HTTPD_REQUEST_HANDLER_FACTORY_I
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user