Compare commits

...

35 Commits
v0 ... v1.0.2

Author SHA1 Message Date
b790c7fd21 cosmetic, cleaning. 2015-06-10 10:59:24 +02:00
9424b1e369 Merge branch 'master' into v1 2015-06-08 10:10:51 +02:00
64463df552 Fixed various compilation error or warning. 2015-06-05 12:17:53 +02:00
dd5c89e31c Fixed compilation of SSL_TCP_STREAM_SOCKET with recent do_accept changes. 2015-05-07 10:44:38 +02:00
fffa763d05 Updated a few comments. 2015-05-06 22:37:55 +02:00
d015c065f6 Updated readme. 2015-05-06 22:18:27 +02:00
8ea443c115 Added abstraction WSF_ROUTED, and WSF_FILTERED.
Added under library/server/obsolete/v0 the previous non concurrent friendly version of EWF/WSF, for backward compatiblity.
Removed WSF_CALLBACK_SERVICE and WSF_TO_WGI_SERVICE which are not need with new EWF.
2015-05-06 22:17:37 +02:00
019393fdb1 Fixed typo. 2015-05-06 22:17:35 +02:00
da8028f8b3 Fixed a typo. 2015-05-06 22:17:33 +02:00
20ed000879 Added a few descriptions and comments. 2015-05-06 22:16:57 +02:00
jvelilla
24620b228c Added feature comments.
Added missing postconditions.
2015-05-06 22:16:10 +02:00
jvelilla
9c7e29b836 Added descriptions and comments 2015-05-06 22:16:08 +02:00
jvelilla
a0e9a41e21 Added descriptions and feature comments. 2015-05-06 22:16:07 +02:00
jvelilla
dd9aff03d3 Added features comments. 2015-05-06 22:16:05 +02:00
jvelilla
dc35925eb0 Added Missing Class and feature descriptions.
Removed author entry.
2015-05-06 22:16:03 +02:00
a1a620a9c3 Export request and response from WGI_EXECUTION to itself.
Added WSF_FILTERED_ROUTED_SKELETON_EXECUTION
2015-05-06 22:16:00 +02:00
d8ea9ba63c renamed keep_alive_requested as is_persistent_connection_requested. 2015-05-06 22:15:59 +02:00
c42af5b2de Following the spec, use "keep-alive" and "close" in lowercase for Connection header. 2015-05-06 22:15:57 +02:00
d9cbc72058 Better support for HTTP/1.0 and also related to persistent connection. 2015-05-06 22:15:56 +02:00
7e057b20b1 Improved support for HTTP/1.0 persistent connection. 2015-05-06 22:15:54 +02:00
3165c1e5c6 Enable support for persistent connections.
(test: works fine with curl -k , but weird behavior with ab -k ...)
2015-05-06 22:15:53 +02:00
89e26519e4 First step to improve a bit error handling related to socket disconnection.
Mainly in standalone connector for now.
2015-05-06 22:15:51 +02:00
9d20e85c03 Improved the simple_file example with image, and not found message.
Use standalone connector in SCOOP concurrency mode.
2015-05-06 22:15:50 +02:00
48cb99498c Cleaned simple example, and made the standalone target with SCOOP concurrency. 2015-05-06 22:15:48 +02:00
8246bc1444 Updated various indexing notes.
Removed a few obsolete classes.
Cosmetics
2015-05-06 22:15:46 +02:00
9e1083eba8 Added migration note. 2015-05-06 22:15:44 +02:00
4907bc3085 Migrated most of the example and library to new design. 2015-05-06 22:15:43 +02:00
7d2ce8a77f Implemented support for base url in httpd connector. 2015-05-06 22:15:38 +02:00
b4a9c92ffc Migrated simple, simple_file and upload_image example.
Adapted EWF accordingly.
2015-05-06 22:14:48 +02:00
bf0eb9a02d Added SCOOP support for WSF.
WSF_SERVICE is deeply changed, and addition of WSF_EXECUTION.
Todo: code cleaning, removing useless things.
2015-05-06 22:13:22 +02:00
ddf73077b3 Support for concurrencies: none, thread and SCOOP 2015-05-06 22:13:19 +02:00
3da80fce0d Finally SCOOP supported. 2015-05-06 22:13:17 +02:00
0970de5dc6 Experiment to avoid pseudo sequential execution 2015-05-06 22:13:15 +02:00
557b11f4e6 First attempt to use `{NETWORK_STREAM_SOCKET}.accept_to' 2015-05-06 22:13:13 +02:00
7f27a6c797 First steps to provide a concurrent compliant EWF connector. 2015-05-06 22:13:11 +02:00
278 changed files with 13182 additions and 3062 deletions

View File

@@ -1,38 +1,7 @@
History for Eiffel-Web-Framework
[2015-06-10]
* Updated EWF design to better support concurrency, including SCOOP via
the new standalone connector.
[2011-09-23] Jocelyn
* library "ewsgi":
- NEW simple autotest cases using Nino web server
-fixed issue with RAW_POST_DATA being added in form_data_parameters
instead of meta_variables ...
- Implemented WGI_VALUE for parameter's type (query_parameter,
form_data_parameter, item ...)
* Nino connector: added feature to shutdown the server from the WGI application
* NEW library "http_client": a new library to perform simple http requests
such as get, head, post, put, ... (currently implemented with Eiffel cURL)
* NEW library "http_authorization": added simple library to support
HTTP_AUTHORIZATION. For now only "Basic" auth type is supported ..
[2011-09-22] Javier
* NEW Example: added partial Restbuck example
[2011-09-21] Jocelyn
* Nino connector: fixed an issue with missing value for Content-Type and Content-Length
[2011-09-13] Jocelyn
* library "router": now using a generic design to allow customization of
request handler context class.
* NEW library "server/request/rest": first attempt to provide a library to
help building RESTful application (the interfaces are likely to change
soon) EXPERIMENTAL
[2011-09-09] Jocelyn
* library "uri-template": better support for {/vars} and {?vars}
[2011-09-07] Jocelyn
* library "router": now routing depends on uri (or uri template) and request methods
* Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable.
[2011-09-07] Jocelyn
* changelog: starting to write down changelogs file
[Previous ] Many significant changes in v0

3138
ChangeLog

File diff suppressed because it is too large Load Diff

121
MIGRATION.md Normal file
View File

@@ -0,0 +1,121 @@
Date: 2015-june
# Goal:
=======
- support safe concurrency with EWF
- provide a concurrent standalone connector
# Status:
=========
- The version v0 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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {CONTACT_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {FLAG_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {BASE_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {CODEVIEW_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS_DATASOURCE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS_REPEATER}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GRID_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {OWN_VALIDATOR}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {INCREASING_PROGRESSSOURCE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {REPEATER_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {SAMPLE_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {SLIDER_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {UPLOAD_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -18,12 +18,21 @@
</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="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
<library name="standalone" location="..\..\library\server\wsf\connector\standalone-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"/>
<setting name="concurrency" value="scoop"/>
<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 +41,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>

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View 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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,82 @@
note
description : "Filter example."
author : "Olivier Ligot"
date : "$Date$"
revision : "$Revision$"
class
FILTER_SERVER_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
redefine
initialize
end
SHARED_EJSON
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_json
end
create_filter
-- Create `filter'
do
create {WSF_CORS_FILTER} filter
end
setup_filter
-- Setup `filter'
local
l_logging_filter: WSF_LOGGING_FILTER
do
create l_logging_filter
filter.set_next (l_logging_filter)
end
setup_router
-- Setup `router'
local
l_options_filter: WSF_CORS_OPTIONS_FILTER
l_authentication_filter: AUTHENTICATION_FILTER
l_user_filter: USER_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_options_filter.make (router)
create l_authentication_filter
create l_user_filter
l_options_filter.set_next (l_authentication_filter)
l_authentication_filter.set_next (l_user_filter)
create l_methods
l_methods.enable_options
l_methods.enable_get
router.handle_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

View File

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

View File

@@ -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="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
<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="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
<target name="restbucks_common">
<file_rule>
<exclude>/EIFGENs$</exclude>
@@ -8,16 +8,16 @@
</file_rule>
<option full_class_checking="false" void_safety="all">
</option>
<setting name="concurrency" value="thread"/>
<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" readonly="false">
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false">
<option debug="true">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
</option>
</library>
<library name="conneg" location="..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf" readonly="false"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
@@ -30,7 +30,7 @@
<target name="restbucks" extends="restbucks_common">
<root class="RESTBUCKS_SERVER" feature="make"/>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<cluster name="src" location="src\" recursive="true">
@@ -42,7 +42,7 @@
<target name="policy_driven_restbucks" extends="restbucks_common">
<root class="RESTBUCKS_SERVER" feature="make"/>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="wsf_policy_driven" location="..\..\library\server\wsf\wsf_policy_driven-safe.ecf" readonly="false"/>

View File

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

View 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

View File

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

View 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

View File

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

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

View File

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

View File

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

View 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

View File

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

View 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

View File

@@ -8,17 +8,17 @@
<exclude>/\.svn$</exclude>
</file_rule>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false" use_application_options="true">
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false" use_application_options="true">
<option>
<assertions precondition="true" check="true" invariant="true" supplier_precondition="true"/>
</option>
</library>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false" use_application_options="true"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false" use_application_options="true"/>
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {HTTP_FORMAT_CONSTANTS}."
description: "Various constants implied in http format."
date: "$Date$"
revision: "$Revision$"

View File

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

View File

@@ -1,6 +1,7 @@
note
description: "Summary description for {NOTIFICATION_CHAIN_MAILER}."
author: ""
description: "[
Node of a notification mailer chain
]"
date: "$Date$"
revision: "$Revision$"

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
]"

View File

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

View File

@@ -0,0 +1,32 @@
note
description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER"
date : "$Date$"
revision : "$Revision$"
deferred class
HTTPD_REQUEST_HANDLER
inherit
HTTPD_REQUEST_HANDLER_I
redefine
is_persistent_connection_supported
end
feature -- Status report
is_persistent_connection_supported: BOOLEAN = False
-- <Precursor>
-- When there is no concurrency support, do not try to support
-- persistent connection!
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More