Compare commits
42 Commits
es_rev1009
...
es_rev1010
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24eb0a4002 | ||
|
|
7d738a164d | ||
|
|
1037256ea6 | ||
|
|
4d79bba04b | ||
|
|
5de024923e | ||
|
|
8b90241986 | ||
|
|
da1c0b8545 | ||
|
|
603bedf71d | ||
|
|
5fedad7f2e | ||
|
|
e83f5654d8 | ||
|
|
25446cac12 | ||
|
|
ccff084642 | ||
|
|
830adbe10c | ||
|
|
e6d998953e | ||
|
|
6ca3cca88b | ||
|
|
f91a676f41 | ||
|
|
1c75e11e34 | ||
|
|
b5b4fa6b2f | ||
|
|
211fc425a3 | ||
|
|
95cebe26bb | ||
|
|
f770c236d5 | ||
|
|
503e5f7915 | ||
|
|
39f01e95fd | ||
|
|
c725159d7e | ||
|
|
e66f1cf7be | ||
|
|
c03d28cabc | ||
|
|
e834b2b360 | ||
|
|
d089fd3a03 | ||
|
|
a8ddd10b46 | ||
|
|
1c9f5ac0e7 | ||
|
|
8ff20d34a7 | ||
|
|
97fe16b4c2 | ||
|
|
cdada71f7e | ||
|
|
a7d0398ec6 | ||
|
|
267655d7bc | ||
|
|
e735da1bcb | ||
|
|
67bdcfb6ef | ||
|
|
ca4043b102 | ||
|
|
310e96e185 | ||
| e14bb568d2 | |||
| 05d37439bc | |||
|
|
99bf552b89 |
@@ -1,10 +1,8 @@
|
|||||||
language: eiffel
|
language: eiffel
|
||||||
before_script:
|
before_script:
|
||||||
- export current_dir=$PWD ; echo current_dir=$current_dir ; cd ..
|
- export current_dir=$PWD ; echo current_dir=$current_dir ; cd ..
|
||||||
- export ISE_VERSION=17.05; export ISE_BUILD=100416
|
- curl -sSL https://www.eiffel.org/setup/install.sh | bash
|
||||||
- curl -sSL http://downloads.sourceforge.net/eiffelstudio/Eiffel_${ISE_VERSION}_gpl_${ISE_BUILD}-linux-x86-64.tar.bz2 | tar -x --bzip2
|
- source eiffel_latest.rc
|
||||||
- export ISE_EIFFEL=$PWD/Eiffel_${ISE_VERSION} ; export ISE_PLATFORM=linux-x86-64
|
|
||||||
- export PATH=$PATH:$ISE_EIFFEL/studio/spec/$ISE_PLATFORM/bin:$PATH:$ISE_EIFFEL/tools/spec/$ISE_PLATFORM/bin
|
|
||||||
- echo `ec -version`
|
- echo `ec -version`
|
||||||
- cd $current_dir
|
- cd $current_dir
|
||||||
- echo Check projects compilation status...
|
- echo Check projects compilation status...
|
||||||
@@ -13,6 +11,7 @@ branches:
|
|||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- v1
|
- v1
|
||||||
|
- develop
|
||||||
|
|
||||||
script: compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false
|
script: compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false
|
||||||
group: stable
|
group: stable
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||||||
- `jwt`: new JSON Web Token (JWT) library (supports for claim exp, iat, nbf, iss, aud).
|
- `jwt`: new JSON Web Token (JWT) library (supports for claim exp, iat, nbf, iss, aud).
|
||||||
- `http_client`: added support for ciphers setting in the libcurl implementation only.
|
- `http_client`: added support for ciphers setting in the libcurl implementation only.
|
||||||
- `http_client`: added convenient `get` and `custom` functions on HTTP_CLIENT directly.
|
- `http_client`: added convenient `get` and `custom` functions on HTTP_CLIENT directly.
|
||||||
|
- `websocket`: added `on_timer` solution to allow the server to check for external events and send notification to websocket clients.
|
||||||
|
- `wsf`: added `WSF_EXECUTE_HANDLER`, and `WSF_CGI_HANDLER`. Demonstration of `WSF_CGI_HANDLER` in the new `tools/httpd` project.
|
||||||
|
- `wsf_security`: new security library, providing support for XSS injection protection and similar.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- adopted ecf version 1-16-0 and use a single .ecf file (the -safe.ecf are now redirection to normal .ecf)
|
- adopted ecf version 1-16-0 and use a single .ecf file (the -safe.ecf are now redirection to normal .ecf)
|
||||||
@@ -22,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||||||
- `http_client`: Added support for multiple file in form data. Made clear what is the meaning of `upload_filename`, `upload_data` and `form_data`.
|
- `http_client`: Added support for multiple file in form data. Made clear what is the meaning of `upload_filename`, `upload_data` and `form_data`.
|
||||||
- `authentication`: HTTP_AUTHORIZATION acceps now READABLE_STRING_GENERAL for username and password argument.
|
- `authentication`: HTTP_AUTHORIZATION acceps now READABLE_STRING_GENERAL for username and password argument.
|
||||||
- `http_client`: fixed curl implementation by setting `Content-Type` to `x-www-form-urlencoded` (if not set) when POST send data as `x-www-form-urlencoded`.
|
- `http_client`: fixed curl implementation by setting `Content-Type` to `x-www-form-urlencoded` (if not set) when POST send data as `x-www-form-urlencoded`.
|
||||||
|
- `notification_email`: fixed the SMTP support for multiple recipients address.
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -13,14 +13,14 @@ Currently EWF offers a collection of Eiffel libraries designed to be integrated
|
|||||||
|
|
||||||
There is a growing ecosystem around EWF, that provides useful components:
|
There is a growing ecosystem around EWF, that provides useful components:
|
||||||
* OpenID and OAuth consumer library
|
* OpenID and OAuth consumer library
|
||||||
* Various hypermedia format such as HAL, Collection+json, …
|
* Various hypermedia format such as HAL, Collection+json, ...
|
||||||
* Websocket server and client
|
* Websocket server and client
|
||||||
* Template engine
|
* Template engine
|
||||||
* API Auto-documentation with swagger
|
* API Auto-documentation with swagger
|
||||||
* A simple experimental CMS.
|
* A simple experimental CMS.
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
So if you want to build a website, a web api, RESTful service, …or even if you want to consume other web api, EWF is a solution.
|
So if you want to build a website, a web api, RESTful service, ... or even if you want to consume other web api, EWF is a solution.
|
||||||
|
|
||||||
EWF brings with it all the advantages of the Eiffel technology and tools with its powerful features such as Design by Contract, debugging, testing tools which enable to build efficient systems expected to be repeatedly refined, extended, and improved in a predictable and controllable way so as to become with time bugfree systems. Enjoy the full power of debugging your web server application from the IDE.
|
EWF brings with it all the advantages of the Eiffel technology and tools with its powerful features such as Design by Contract, debugging, testing tools which enable to build efficient systems expected to be repeatedly refined, extended, and improved in a predictable and controllable way so as to become with time bugfree systems. Enjoy the full power of debugging your web server application from the IDE.
|
||||||
|
|
||||||
@@ -51,11 +51,11 @@ Tasks and issues are managed with github issue system
|
|||||||
## How to get the source code?
|
## How to get the source code?
|
||||||
|
|
||||||
Using git
|
Using git
|
||||||
* git clone https://github.com/EiffelWebFramework/EWF.git
|
* `git clone https://github.com/EiffelWebFramework/EWF.git`
|
||||||
|
|
||||||
* And to build the required and related Clibs
|
* And to build the required and related Clibs
|
||||||
* cd contrib/ise_library/cURL
|
* `cd contrib/ise_library/cURL`
|
||||||
* geant compile
|
* `geant compile`
|
||||||
|
|
||||||
## Libraries under 'library'
|
## Libraries under 'library'
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ Using git
|
|||||||
* connectors: various web server connectors for EWSGI
|
* connectors: various web server connectors for EWSGI
|
||||||
* libfcgi: Wrapper for libfcgi SDK
|
* libfcgi: Wrapper for libfcgi SDK
|
||||||
* __wsf__: Web Server Framework [read more](library/server/wsf)
|
* __wsf__: Web Server Framework [read more](library/server/wsf)
|
||||||
* __router__: URL dispatching/routing based on uri, uri_template, or custom [read more](library/server/wsf/router)
|
* __router__: URL dispatching/routing based on `uri`, `uri_template`, or custom [read more](library/server/wsf/router)
|
||||||
|
|
||||||
### protocol
|
### protocol
|
||||||
* __http__: HTTP related classes, constants for status code, content types, ... [read more](library/network/protocol/http)
|
* __http__: HTTP related classes, constants for status code, content types, ... [read more](library/network/protocol/http)
|
||||||
|
|||||||
4
examples/simple_compression/service.ini
Normal file
4
examples/simple_compression/service.ini
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
port=9090
|
||||||
|
verbose=true
|
||||||
|
socket_recv_timeout=15
|
||||||
|
keep_alive_timeout=30
|
||||||
26
examples/simple_compression/service_compression.e
Normal file
26
examples/simple_compression/service_compression.e
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
note
|
||||||
|
description : "simple application root class"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
SERVICE_COMPRESSION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_DEFAULT_SERVICE [SERVICE_COMPRESSION_EXECUTION]
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
do
|
||||||
|
Precursor
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("service.ini"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
22
examples/simple_compression/service_compression.ecf
Normal file
22
examples/simple_compression/service_compression.ecf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="service_compression" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
|
||||||
|
<target name="service_compression">
|
||||||
|
<root class="SERVICE_COMPRESSION" feature="make_and_launch"/>
|
||||||
|
<option warning="true" void_safety="all">
|
||||||
|
<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="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" readonly="false"/>
|
||||||
|
<library name="wsf_compression" location="..\..\library\server\wsf\wsf_compression-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="service_compression" location=".\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
68
examples/simple_compression/service_compression_execution.e
Normal file
68
examples/simple_compression/service_compression_execution.e
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
note
|
||||||
|
description: "Simple file execution, serving home.html, ewf.png and 404.html"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
SERVICE_COMPRESSION_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTED_EXECUTION
|
||||||
|
redefine
|
||||||
|
initialize,
|
||||||
|
execute_default
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
Precursor
|
||||||
|
initialize_router
|
||||||
|
end
|
||||||
|
|
||||||
|
setup_router
|
||||||
|
local
|
||||||
|
fhdl_with_compression: WSF_FILE_SYSTEM_HANDLER_WITH_COMPRESSION
|
||||||
|
fhdl: WSF_FILE_SYSTEM_HANDLER
|
||||||
|
do
|
||||||
|
create fhdl_with_compression.make_hidden ("www")
|
||||||
|
fhdl_with_compression.set_directory_index (<<"index.html">>)
|
||||||
|
fhdl_with_compression.compression.set_default_compression_format
|
||||||
|
fhdl_with_compression.compression.enable_compression_for_media_type ({HTTP_MIME_TYPES}.image_jpg)
|
||||||
|
fhdl_with_compression.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
execute_default (ia_req, ia_res)
|
||||||
|
end)
|
||||||
|
router.handle ("/compressed/", fhdl_with_compression, router.methods_GET)
|
||||||
|
|
||||||
|
create fhdl.make_hidden ("www")
|
||||||
|
fhdl.set_directory_index (<<"index.html">>)
|
||||||
|
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
execute_default (ia_req, ia_res)
|
||||||
|
end)
|
||||||
|
router.handle ("/", fhdl, router.methods_GET)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Dispatch requests without a matching handler.
|
||||||
|
local
|
||||||
|
not_found: WSF_NOT_FOUND_RESPONSE
|
||||||
|
mesg: WSF_RESPONSE_MESSAGE
|
||||||
|
do
|
||||||
|
create not_found.make (request)
|
||||||
|
not_found.add_suggested_location (request.absolute_script_url (""), "Home", "Back to home page")
|
||||||
|
mesg := not_found
|
||||||
|
res.send (mesg)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
77705
examples/simple_compression/www/big_file.html
Normal file
77705
examples/simple_compression/www/big_file.html
Normal file
File diff suppressed because it is too large
Load Diff
88332
examples/simple_compression/www/big_file2.html
Normal file
88332
examples/simple_compression/www/big_file2.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
examples/simple_compression/www/eiffel.jpg
Normal file
BIN
examples/simple_compression/www/eiffel.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
examples/simple_compression/www/ewf.png
Normal file
BIN
examples/simple_compression/www/ewf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
27
examples/simple_compression/www/index.html
Normal file
27
examples/simple_compression/www/index.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>EWF simple_file example</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<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>
|
||||||
|
<div width="45%" style="display: inline-block; border: solid 1px black; padding: 10px; margin: 10px;">
|
||||||
|
<h2>Without any compression</h2>
|
||||||
|
<a href="ewf.png"><img src="ewf.png"/></a>
|
||||||
|
<p>This is the real Eiffel tower.</p>
|
||||||
|
<a href="eiffel.jpg"><img src="eiffel.jpg"/></a>
|
||||||
|
<p>Try to <a href="big_file2.html">load a big file</a>.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div width="45%" style="display: inline-block; border: solid 1px black; padding: 10px; margin: 10px;">
|
||||||
|
<h2>With gzip compression</h2>
|
||||||
|
<a href="compressed/ewf.png"><img src="compressed/ewf.png"/></a>
|
||||||
|
<p>This is the real Eiffel tower.</p>
|
||||||
|
<a href="compressed/eiffel.jpg"><img src="compressed/eiffel.jpg"/></a>
|
||||||
|
<p>Try to <a href="compressed/big_file2.html">load a compressed big file</a>.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -10,6 +10,9 @@ inherit
|
|||||||
WSF_WEBSOCKET_EXECUTION
|
WSF_WEBSOCKET_EXECUTION
|
||||||
|
|
||||||
WEB_SOCKET_EVENT_I
|
WEB_SOCKET_EVENT_I
|
||||||
|
redefine
|
||||||
|
on_timer
|
||||||
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
@@ -52,6 +55,9 @@ feature -- Websocket execution
|
|||||||
|
|
||||||
on_open (ws: WEB_SOCKET)
|
on_open (ws: WEB_SOCKET)
|
||||||
do
|
do
|
||||||
|
initialize_commands
|
||||||
|
set_timer_delay (1) -- Every 1 second.
|
||||||
|
|
||||||
ws.put_error ("Connecting")
|
ws.put_error ("Connecting")
|
||||||
ws.send (Text_frame, "Hello, this is a simple demo with Websocket using Eiffel. (/help for more information).%N")
|
ws.send (Text_frame, "Hello, this is a simple demo with Websocket using Eiffel. (/help for more information).%N")
|
||||||
end
|
end
|
||||||
@@ -62,12 +68,26 @@ feature -- Websocket execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
on_text (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
on_text (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
i: INTEGER
|
||||||
|
cmd_name: READABLE_STRING_8
|
||||||
do
|
do
|
||||||
if a_message.same_string_general ("/help") then
|
if a_message.starts_with_general ("/") then
|
||||||
-- Echo the message for testing.
|
from
|
||||||
ws.send (Text_frame, "Help: available commands%N - /time : return the server UTC time.%N")
|
i := 1
|
||||||
elseif a_message.starts_with_general ("/time") then
|
until
|
||||||
ws.send (Text_frame, "Server time is " + (create {HTTP_DATE}.make_now_utc).string)
|
i >= a_message.count or else a_message[i + 1].is_space
|
||||||
|
loop
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
cmd_name := a_message.substring (2, i)
|
||||||
|
if attached command (cmd_name) as cmd then
|
||||||
|
cmd (ws, a_message.substring (i + 1, a_message.count))
|
||||||
|
elseif a_message.same_string_general ("/help") then
|
||||||
|
on_help_command (ws, Void)
|
||||||
|
else
|
||||||
|
ws.send (Text_frame, "Error: unknown command '/" + cmd_name + "'!%N")
|
||||||
|
end
|
||||||
else
|
else
|
||||||
-- Echo the message for testing.
|
-- Echo the message for testing.
|
||||||
ws.send (Text_frame, a_message)
|
ws.send (Text_frame, a_message)
|
||||||
@@ -80,6 +100,88 @@ feature -- Websocket execution
|
|||||||
ws.put_error ("Connection closed")
|
ws.put_error ("Connection closed")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
on_timer (ws: WEB_SOCKET)
|
||||||
|
-- <Precursor>.
|
||||||
|
-- If ever the file ".stop" exists, stop gracefully the connection.
|
||||||
|
local
|
||||||
|
fut: FILE_UTILITIES
|
||||||
|
f: RAW_FILE
|
||||||
|
do
|
||||||
|
if fut.file_exists (".stop") then
|
||||||
|
ws.send_text ("End of the communication ...%N")
|
||||||
|
ws.send_connection_close ("")
|
||||||
|
create f.make_with_name (".stop")
|
||||||
|
f.delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Command
|
||||||
|
|
||||||
|
initialize_commands
|
||||||
|
do
|
||||||
|
register_command (agent on_help_command, "help", "Display this help.")
|
||||||
|
register_command (agent on_time_command, "time", "Return the server UTC time.")
|
||||||
|
register_command (agent on_shutdown_command, "shutdown", "Shutdown the service (ends the websocket).")
|
||||||
|
end
|
||||||
|
|
||||||
|
register_command (a_cmd: attached like command; a_name: READABLE_STRING_8; a_description: READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
tb: like commands
|
||||||
|
do
|
||||||
|
tb := commands
|
||||||
|
if tb = Void then
|
||||||
|
create tb.make_caseless (1)
|
||||||
|
commands := tb
|
||||||
|
end
|
||||||
|
tb.force ([a_cmd, a_name, a_description], a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
commands: detachable STRING_TABLE [TUPLE [cmd: attached like command; name, description: READABLE_STRING_8]]
|
||||||
|
|
||||||
|
command (a_name: READABLE_STRING_GENERAL): detachable PROCEDURE [TUPLE [ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL]]
|
||||||
|
do
|
||||||
|
if
|
||||||
|
attached commands as tb and then
|
||||||
|
attached tb.item (a_name) as d
|
||||||
|
then
|
||||||
|
Result := d.cmd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_help_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
create s.make_from_string ("Help: available commands:%N")
|
||||||
|
if attached commands as tb then
|
||||||
|
across
|
||||||
|
tb as ic
|
||||||
|
loop
|
||||||
|
s.append ("<li> /")
|
||||||
|
s.append (ic.item.name)
|
||||||
|
s.append (" : ")
|
||||||
|
s.append (ic.item.description)
|
||||||
|
s.append ("</li>%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ws.send_text (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
on_time_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
|
||||||
|
do
|
||||||
|
ws.send_text ("Server time is " + (create {HTTP_DATE}.make_now_utc).string)
|
||||||
|
end
|
||||||
|
|
||||||
|
on_shutdown_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
|
||||||
|
local
|
||||||
|
f: RAW_FILE
|
||||||
|
do
|
||||||
|
ws.send_text ("Active websockets will end soon.%N")
|
||||||
|
create f.make_create_read_write (".stop")
|
||||||
|
f.put_string ("stop%N")
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
|
||||||
feature -- HTML Resource
|
feature -- HTML Resource
|
||||||
|
|
||||||
websocket_app_html (a_port: INTEGER): STRING
|
websocket_app_html (a_port: INTEGER): STRING
|
||||||
@@ -188,5 +290,4 @@ body {font-family:Arial, Helvetica, sans-serif;}
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ feature {NONE} -- Initialization
|
|||||||
i := a_url.substring_index ("://", 1)
|
i := a_url.substring_index ("://", 1)
|
||||||
if i > 0 then
|
if i > 0 then
|
||||||
check
|
check
|
||||||
a_url.substring (1, i).same_string ("http")
|
a_url.head (i - 1).same_string ("http")
|
||||||
or a_url.substring (1, i).same_string ("https")
|
or a_url.head (i - 1).same_string ("https")
|
||||||
end
|
end
|
||||||
url := a_url
|
url := a_url
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -61,12 +61,40 @@ feature -- Access
|
|||||||
url (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): STRING_8
|
url (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): STRING_8
|
||||||
-- Url computed from Current and `ctx' data.
|
-- Url computed from Current and `ctx' data.
|
||||||
do
|
do
|
||||||
Result := base_url + a_path
|
if is_absolute_url (a_path) then
|
||||||
|
-- Is Absolute url
|
||||||
|
Result := a_path
|
||||||
|
else
|
||||||
|
Result := base_url + a_path
|
||||||
|
end
|
||||||
if ctx /= Void then
|
if ctx /= Void then
|
||||||
ctx.append_query_parameters_to_url (Result)
|
ctx.append_query_parameters_to_url (Result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_absolute_url (s: READABLE_STRING_GENERAL): BOOLEAN
|
||||||
|
-- Does `s` represent an absolute url?
|
||||||
|
local
|
||||||
|
i, pos: INTEGER
|
||||||
|
sch: READABLE_STRING_GENERAL
|
||||||
|
do
|
||||||
|
pos := s.substring_index ("://", 1)
|
||||||
|
if pos > 0 then
|
||||||
|
sch := s.head (pos - 1)
|
||||||
|
if not sch.is_whitespace then
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
Result := True
|
||||||
|
until
|
||||||
|
not Result or i > sch.count
|
||||||
|
loop
|
||||||
|
Result := sch[i].is_alpha_numeric
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature {NONE} -- Access: verbose
|
feature {NONE} -- Access: verbose
|
||||||
|
|
||||||
verbose_mode: INTEGER
|
verbose_mode: INTEGER
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ note
|
|||||||
deferred class
|
deferred class
|
||||||
HTTP_CLIENT_REQUEST_PARAMETER
|
HTTP_CLIENT_REQUEST_PARAMETER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
name: READABLE_STRING_32
|
name: READABLE_STRING_32
|
||||||
@@ -18,6 +21,15 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
debug_output: STRING_32
|
||||||
|
do
|
||||||
|
create Result.make_empty
|
||||||
|
Result.append (name)
|
||||||
|
Result.append ("=...")
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Conversion
|
feature -- Conversion
|
||||||
|
|
||||||
append_form_url_encoded_to (a_output: STRING_8)
|
append_form_url_encoded_to (a_output: STRING_8)
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ feature -- Access
|
|||||||
Result := items.count
|
Result := items.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
has (a_parameter_name: READABLE_STRING_GENERAL): BOOLEAN
|
||||||
|
do
|
||||||
|
Result := across items as ic some a_parameter_name.same_string (ic.item.name) end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Element change
|
feature -- Element change
|
||||||
|
|
||||||
extend, force (i: G)
|
extend, force (i: G)
|
||||||
|
|||||||
@@ -74,6 +74,22 @@ feature -- Test routines
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_abs_url
|
||||||
|
local
|
||||||
|
sess: like new_session
|
||||||
|
h: STRING_8
|
||||||
|
l_url: STRING
|
||||||
|
do
|
||||||
|
sess := new_session ("https://www.eiffel.org")
|
||||||
|
l_url := "/foo/bar"
|
||||||
|
assert ("abs rel", sess.url (l_url, Void).same_string (sess.base_url + l_url))
|
||||||
|
|
||||||
|
l_url := "https://www.eiffel.org/foo/bar"
|
||||||
|
assert ("abs 1", sess.url (l_url, Void).same_string (l_url))
|
||||||
|
l_url := "https://example.com/foo/bar"
|
||||||
|
assert ("abs 2", sess.url (l_url, Void).same_string (l_url))
|
||||||
|
end
|
||||||
|
|
||||||
test_headers
|
test_headers
|
||||||
local
|
local
|
||||||
res: HTTP_CLIENT_RESPONSE
|
res: HTTP_CLIENT_RESPONSE
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ feature -- Tests
|
|||||||
test_http_client_ssl
|
test_http_client_ssl
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_libcurl_abs_url
|
||||||
|
do
|
||||||
|
test_abs_url
|
||||||
|
end
|
||||||
|
|
||||||
test_libcurl_headers
|
test_libcurl_headers
|
||||||
do
|
do
|
||||||
test_headers
|
test_headers
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ feature -- Tests
|
|||||||
test_http_client_ssl
|
test_http_client_ssl
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_net_abs_url
|
||||||
|
do
|
||||||
|
test_abs_url
|
||||||
|
end
|
||||||
|
|
||||||
test_net_headers
|
test_net_headers
|
||||||
do
|
do
|
||||||
test_headers
|
test_headers
|
||||||
|
|||||||
@@ -95,40 +95,67 @@ feature -- Basic operation
|
|||||||
l_email: EMAIL
|
l_email: EMAIL
|
||||||
h: STRING
|
h: STRING
|
||||||
i: INTEGER
|
i: INTEGER
|
||||||
|
lst: LIST [READABLE_STRING_8]
|
||||||
do
|
do
|
||||||
create l_email.make_with_entry (a_email.from_address, addresses_to_header_line_value (a_email.to_addresses))
|
lst := a_email.to_addresses
|
||||||
if attached a_email.reply_to_address as l_reply_to then
|
if lst.is_empty then
|
||||||
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_reply_to, l_reply_to)
|
-- Error ...
|
||||||
end
|
else
|
||||||
|
-- With EMAIL, there should be a unique recipient at creation.
|
||||||
if attached a_email.cc_addresses as lst then
|
create l_email.make_with_entry (a_email.from_address, lst.first)
|
||||||
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_cc, addresses_to_header_line_value (lst))
|
if lst.count > 1 then
|
||||||
end
|
from
|
||||||
if attached a_email.bcc_addresses as lst then
|
lst.start
|
||||||
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_bcc, addresses_to_header_line_value (lst))
|
lst.forth
|
||||||
end
|
until
|
||||||
l_email.set_message (a_email.content)
|
lst.off
|
||||||
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, a_email.subject)
|
loop
|
||||||
|
l_email.add_recipient_address (lst.item)
|
||||||
create h.make_empty
|
lst.forth
|
||||||
;(create {HTTP_DATE}.make_from_date_time (a_email.date)).append_to_rfc1123_string (h)
|
|
||||||
l_email.add_header_entry ("Date", h)
|
|
||||||
|
|
||||||
if attached a_email.additional_header_lines as lst then
|
|
||||||
across
|
|
||||||
lst as ic
|
|
||||||
loop
|
|
||||||
h := ic.item
|
|
||||||
i := h.index_of (':', 1)
|
|
||||||
if i > 0 then
|
|
||||||
l_email.add_header_entry (h.head (i - 1), h.substring (i + 1, h.count))
|
|
||||||
else
|
|
||||||
check is_header_line: False end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
if attached a_email.reply_to_address as l_reply_to then
|
||||||
|
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_reply_to, l_reply_to)
|
||||||
|
end
|
||||||
|
|
||||||
smtp_send_email (l_email)
|
if attached a_email.cc_addresses as l_cc_addresses then
|
||||||
|
across
|
||||||
|
l_cc_addresses as ic
|
||||||
|
loop
|
||||||
|
l_email.add_recipient_address_in_cc (ic.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if attached a_email.bcc_addresses as l_bcc_addresses then
|
||||||
|
across
|
||||||
|
l_bcc_addresses as ic
|
||||||
|
loop
|
||||||
|
l_email.add_recipient_address_in_bcc (ic.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_email.set_message (a_email.content)
|
||||||
|
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, a_email.subject)
|
||||||
|
|
||||||
|
create h.make_empty
|
||||||
|
;(create {HTTP_DATE}.make_from_date_time (a_email.date)).append_to_rfc1123_string (h)
|
||||||
|
l_email.add_header_entry ("Date", h)
|
||||||
|
|
||||||
|
if attached a_email.additional_header_lines as l_lines then
|
||||||
|
across
|
||||||
|
l_lines as ic
|
||||||
|
loop
|
||||||
|
h := ic.item
|
||||||
|
i := h.index_of (':', 1)
|
||||||
|
if i > 0 then
|
||||||
|
l_email.add_header_entry (h.head (i - 1), h.substring (i + 1, h.count))
|
||||||
|
else
|
||||||
|
check is_header_line: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
smtp_send_email (l_email)
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
@@ -182,4 +209,3 @@ note
|
|||||||
Customer support http://support.eiffel.com
|
Customer support http://support.eiffel.com
|
||||||
]"
|
]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
||||||
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
|
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
|
||||||
<library name="http" location="..\..\..\..\network\protocol\http\http.ecf"/>
|
<library name="http" location="..\..\..\..\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="process" location="$ISE_LIBRARY\library\process\base\base_process.ecf"/>
|
||||||
<library name="wsf" location="wsf.ecf"/>
|
<library name="wsf" location="wsf.ecf"/>
|
||||||
<library name="wsf_router_context" location="wsf_router_context.ecf" readonly="true"/>
|
<library name="wsf_router_context" location="wsf_router_context.ecf" readonly="true"/>
|
||||||
<cluster name="extension" location="..\..\..\wsf\extension\" recursive="true"/>
|
<cluster name="extension" location="..\..\..\wsf\extension\" recursive="true"/>
|
||||||
|
|||||||
205
library/server/wsf/compression/wsf_compression.e
Normal file
205
library/server/wsf/compression/wsf_compression.e
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_COMPRESSION}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_COMPRESSION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
-- Initialize compression support, by default no compression
|
||||||
|
-- Gzip with the following media types
|
||||||
|
-- applications/javascript
|
||||||
|
-- application/json
|
||||||
|
-- application/xml
|
||||||
|
-- text/css
|
||||||
|
-- text/html
|
||||||
|
--
|
||||||
|
do
|
||||||
|
-- compression algorithms
|
||||||
|
create {ARRAYED_LIST [STRING]} compression_supported_formats.make (0)
|
||||||
|
compression_supported_formats.compare_objects
|
||||||
|
|
||||||
|
-- media types supported by compression.
|
||||||
|
create {ARRAYED_LIST [STRING]} compression_enabled_media_types.make (0)
|
||||||
|
compression_enabled_media_types.compare_objects
|
||||||
|
set_default_compression_enabled_media_types
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Query
|
||||||
|
|
||||||
|
encoding_variants (req: WSF_REQUEST; ct: STRING): detachable HTTP_ACCEPT_ENCODING_VARIANTS
|
||||||
|
-- If the client support compression and the server support one of the algorithms
|
||||||
|
-- compress it and update the response header.
|
||||||
|
local
|
||||||
|
conneg : SERVER_CONTENT_NEGOTIATION
|
||||||
|
do
|
||||||
|
if
|
||||||
|
attached req.http_accept_encoding as l_http_encoding and then
|
||||||
|
not compression_supported_formats.is_empty and then
|
||||||
|
compression_enabled_media_types.has (ct)
|
||||||
|
then
|
||||||
|
create conneg.make ("", "", "", "")
|
||||||
|
Result := conneg.encoding_preference (compression_supported_formats, l_http_encoding)
|
||||||
|
if not Result.is_acceptable then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Compression: constants
|
||||||
|
|
||||||
|
gzip_compression_format: STRING = "gzip"
|
||||||
|
-- RFC 1952 (gzip compressed format).
|
||||||
|
|
||||||
|
deflate_compression_format: STRING = "deflate"
|
||||||
|
-- RFC 1951 (deflate compressed format).
|
||||||
|
|
||||||
|
compress_compression_format: STRING = "compress"
|
||||||
|
-- RFC 1950 (zlib compressed format).
|
||||||
|
|
||||||
|
feature -- Compression
|
||||||
|
|
||||||
|
compression_supported_formats : LIST [STRING]
|
||||||
|
-- Server side compression supported formats.
|
||||||
|
-- Supported compression agorithms: `gzip_compression_format', `deflate_compression_format', `compress_compression_format'.
|
||||||
|
-- identity, means no compression at all.
|
||||||
|
|
||||||
|
compression_enabled_media_types: LIST [STRING]
|
||||||
|
-- List of media types supported by compression.
|
||||||
|
|
||||||
|
set_default_compression_format
|
||||||
|
-- gzip default format.
|
||||||
|
do
|
||||||
|
enable_gzip_compression
|
||||||
|
end
|
||||||
|
|
||||||
|
disable_all_compression_formats
|
||||||
|
-- Remove all items.
|
||||||
|
do
|
||||||
|
compression_supported_formats.wipe_out
|
||||||
|
end
|
||||||
|
|
||||||
|
enable_gzip_compression
|
||||||
|
-- add 'gzip' format to the list of 'compression_supported' formats.
|
||||||
|
do
|
||||||
|
compression_supported_formats.force (gzip_compression_format)
|
||||||
|
ensure
|
||||||
|
has_gzip: compression_supported_formats.has (gzip_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
disable_gzip_compression
|
||||||
|
-- remove 'gzip' format to the list of 'compression_supported' formats.
|
||||||
|
do
|
||||||
|
compression_supported_formats.prune (gzip_compression_format)
|
||||||
|
ensure
|
||||||
|
not_gzip: not compression_supported_formats.has (gzip_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
enable_deflate_compression
|
||||||
|
-- add 'deflate' format to the list of 'compression_supported' formats.
|
||||||
|
do
|
||||||
|
compression_supported_formats.force (deflate_compression_format)
|
||||||
|
ensure
|
||||||
|
has_deflate: compression_supported_formats.has (deflate_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
disable_deflate_compression
|
||||||
|
-- remove 'deflate' format to the list of 'compression_supported' formats.
|
||||||
|
do
|
||||||
|
compression_supported_formats.prune (deflate_compression_format)
|
||||||
|
ensure
|
||||||
|
not_deflate: not compression_supported_formats.has (deflate_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
enable_compress_compression
|
||||||
|
-- add 'compress' format to the list of 'compression_supported' formats
|
||||||
|
do
|
||||||
|
compression_supported_formats.force (compress_compression_format)
|
||||||
|
ensure
|
||||||
|
has_compress: compression_supported_formats.has (compress_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
disable_compress_compression
|
||||||
|
-- remove 'deflate' format to the list of 'compression_supported' formats.
|
||||||
|
do
|
||||||
|
compression_supported_formats.prune (compress_compression_format)
|
||||||
|
ensure
|
||||||
|
no_compress: not compression_supported_formats.has (compress_compression_format)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Compression: media types
|
||||||
|
|
||||||
|
set_default_compression_enabled_media_types
|
||||||
|
-- Default media types
|
||||||
|
-- applications/javascript
|
||||||
|
-- application/json
|
||||||
|
-- application/xml
|
||||||
|
-- text/css
|
||||||
|
-- text/html
|
||||||
|
-- text/plain
|
||||||
|
do
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.application_javascript)
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.application_json)
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.application_xml)
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.text_css)
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.text_html)
|
||||||
|
compression_enabled_media_types.force ({HTTP_MIME_TYPES}.text_plain)
|
||||||
|
end
|
||||||
|
|
||||||
|
remove_all_compression_enabled_media_types
|
||||||
|
-- Remove all items.
|
||||||
|
do
|
||||||
|
compression_enabled_media_types.wipe_out
|
||||||
|
end
|
||||||
|
|
||||||
|
enable_compression_for_media_type (a_media_type: STRING)
|
||||||
|
do
|
||||||
|
compression_enabled_media_types.force (a_media_type)
|
||||||
|
ensure
|
||||||
|
has_media_type: compression_enabled_media_types.has (a_media_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Compress Data
|
||||||
|
|
||||||
|
compressed_string (a_string: STRING; a_encoding: STRING): STRING
|
||||||
|
-- Compress `a_string' using `deflate_compression_format'
|
||||||
|
local
|
||||||
|
dc: ZLIB_STRING_COMPRESS
|
||||||
|
do
|
||||||
|
create Result.make_empty
|
||||||
|
create dc.string_stream_with_size (Result, 32_768) -- chunk size 32k
|
||||||
|
dc.put_string_with_options (a_string, {ZLIB_CONSTANTS}.Z_default_compression, zlb_strategy (a_encoding), {ZLIB_CONSTANTS}.Z_mem_level_9, {ZLIB_CONSTANTS}.z_default_strategy.to_integer_32)
|
||||||
|
-- We use the default compression level
|
||||||
|
-- We use the default value for windows bits, the range is 8..15. Higher values use more memory, but produce smaller output.
|
||||||
|
-- Memory: Higher values use more memory, but are faster and produce smaller output. The default is 8, we use 9.
|
||||||
|
end
|
||||||
|
|
||||||
|
zlb_strategy (a_encoding: STRING): INTEGER
|
||||||
|
do
|
||||||
|
if a_encoding.is_case_insensitive_equal_general (gzip_compression_format) then
|
||||||
|
Result := {ZLIB_CONSTANTS}.z_default_window_bits + 16
|
||||||
|
elseif a_encoding.is_case_insensitive_equal_general (deflate_compression_format) then
|
||||||
|
Result := -{ZLIB_CONSTANTS}.z_default_window_bits
|
||||||
|
else
|
||||||
|
check compress: a_encoding.is_case_insensitive_equal_general (compress_compression_format) end
|
||||||
|
Result := {ZLIB_CONSTANTS}.z_default_window_bits
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_FILE_RESPONSE_WITH_COMPRESSION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_FILE_RESPONSE_WITH_COMPRESSION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_FILE_RESPONSE
|
||||||
|
redefine
|
||||||
|
send_to
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_with_path,
|
||||||
|
make_with_content_type_and_path,
|
||||||
|
make_html_with_path,
|
||||||
|
make,
|
||||||
|
make_with_content_type,
|
||||||
|
make_html
|
||||||
|
|
||||||
|
feature {NONE} -- Access
|
||||||
|
|
||||||
|
compression_variants: detachable HTTP_ACCEPT_ENCODING_VARIANTS
|
||||||
|
|
||||||
|
compression: detachable WSF_COMPRESSION
|
||||||
|
|
||||||
|
feature -- Compression setting
|
||||||
|
|
||||||
|
apply_compression (a_compression: WSF_COMPRESSION; req: WSF_REQUEST)
|
||||||
|
do
|
||||||
|
compression := a_compression
|
||||||
|
compression_variants := a_compression.encoding_variants (req, content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
reset_compression
|
||||||
|
do
|
||||||
|
compression := Void
|
||||||
|
compression_variants := Void
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {WSF_RESPONSE} -- Output
|
||||||
|
|
||||||
|
send_to (res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
if status_code = {HTTP_STATUS_CODE}.not_found then
|
||||||
|
-- File not found, then no more data.
|
||||||
|
elseif
|
||||||
|
attached compression as l_compression and then
|
||||||
|
attached compression_variants as l_compression_variants and then
|
||||||
|
attached l_compression_variants.encoding as l_encoding and then
|
||||||
|
attached l_compression_variants.vary_header_value as l_vary_header
|
||||||
|
then
|
||||||
|
send_compressed_to (res, l_compression, l_encoding, l_vary_header)
|
||||||
|
else
|
||||||
|
-- Send uncompressed...
|
||||||
|
Precursor (res)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
send_compressed_to (res: WSF_RESPONSE; a_compression: WSF_COMPRESSION; a_comp_encoding, a_comp_vary_header: READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
s: detachable READABLE_STRING_8
|
||||||
|
l_content, l_compressed_content: STRING_8
|
||||||
|
f: RAW_FILE
|
||||||
|
l_count: INTEGER
|
||||||
|
do
|
||||||
|
res.set_status_code (status_code)
|
||||||
|
create f.make_with_path (file_path)
|
||||||
|
l_count := f.count
|
||||||
|
f.open_read
|
||||||
|
f.read_stream (l_count)
|
||||||
|
f.close
|
||||||
|
l_content := f.last_string
|
||||||
|
|
||||||
|
s := head
|
||||||
|
if s /= Void then
|
||||||
|
l_content.prepend (s)
|
||||||
|
end
|
||||||
|
s := bottom
|
||||||
|
if s /= Void then
|
||||||
|
l_content.append_string (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
l_compressed_content := a_compression.compressed_string (l_content, a_comp_encoding)
|
||||||
|
|
||||||
|
debug
|
||||||
|
res.put_error (l_content.count.out + " -(compression-> " + l_compressed_content.count.out + "%N")
|
||||||
|
end
|
||||||
|
header.put_content_encoding (a_comp_encoding)
|
||||||
|
header.add_header ("Vary:" + a_comp_vary_header)
|
||||||
|
header.put_content_length (l_compressed_content.count)
|
||||||
|
|
||||||
|
res.put_header_text (header.string)
|
||||||
|
if not answer_head_request_method then
|
||||||
|
res.put_string (l_compressed_content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_FILE_SYSTEM_HANDLER_WITH_COMPRESSION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_FILE_SYSTEM_HANDLER_WITH_COMPRESSION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_FILE_SYSTEM_HANDLER
|
||||||
|
redefine
|
||||||
|
initialize,
|
||||||
|
process_transfert
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_with_path,
|
||||||
|
make_hidden_with_path,
|
||||||
|
make,
|
||||||
|
make_hidden
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
do
|
||||||
|
Precursor
|
||||||
|
create compression.make
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: compression
|
||||||
|
|
||||||
|
compression: WSF_COMPRESSION
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
local
|
||||||
|
ext: READABLE_STRING_32
|
||||||
|
ct: detachable READABLE_STRING_8
|
||||||
|
fres: WSF_FILE_RESPONSE_WITH_COMPRESSION
|
||||||
|
dt: DATE_TIME
|
||||||
|
do
|
||||||
|
ext := extension (f.path.name)
|
||||||
|
ct := extension_mime_mapping.mime_type (ext)
|
||||||
|
if ct = Void then
|
||||||
|
ct := {HTTP_MIME_TYPES}.application_force_download
|
||||||
|
end
|
||||||
|
|
||||||
|
create fres.make_with_content_type_and_path (ct, f.path)
|
||||||
|
-- Apply compression based on request `req` header.
|
||||||
|
fres.apply_compression (compression, req)
|
||||||
|
|
||||||
|
-- Prepare response
|
||||||
|
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
|
|
||||||
|
-- cache control
|
||||||
|
create dt.make_now_utc
|
||||||
|
fres.header.put_utc_date (dt)
|
||||||
|
if max_age >= 0 then
|
||||||
|
fres.set_max_age (max_age)
|
||||||
|
if max_age > 0 then
|
||||||
|
dt := dt.twin
|
||||||
|
dt.second_add (max_age)
|
||||||
|
end
|
||||||
|
fres.set_expires_date (dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send
|
||||||
|
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
|
||||||
|
res.send (fres)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -88,6 +88,23 @@ feature -- Websocket events
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {WEB_SOCKET} -- Timeout.
|
||||||
|
|
||||||
|
timer_delay: INTEGER
|
||||||
|
-- Maximal duration in seconds between two `on_timeout` event.
|
||||||
|
-- Disable timeout event, by setting it to `0` (default).
|
||||||
|
|
||||||
|
set_timer_delay (nb_secs: INTEGER)
|
||||||
|
do
|
||||||
|
timer_delay := nb_secs
|
||||||
|
end
|
||||||
|
|
||||||
|
on_timer (ws: WEB_SOCKET)
|
||||||
|
-- Called every `timer_delay` seconds.
|
||||||
|
-- Note: redefine to use.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Websocket events: implemented
|
feature -- Websocket events: implemented
|
||||||
|
|
||||||
on_pong (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
on_pong (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
||||||
@@ -126,7 +143,7 @@ feature -- Websocket events: implemented
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
Object representing the websocket connection.
|
Object representing the websocket connection.
|
||||||
It contains the `request` and `response`, and more important the `socket` itself.
|
It contains internally the `request` and `response`, and more important the `socket` itself.
|
||||||
]"
|
]"
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
@@ -10,16 +10,14 @@ class
|
|||||||
WEB_SOCKET
|
WEB_SOCKET
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WEB_SOCKET_WRITER
|
||||||
|
|
||||||
WGI_STANDALONE_CONNECTOR_EXPORTER
|
WGI_STANDALONE_CONNECTOR_EXPORTER
|
||||||
|
|
||||||
WSF_RESPONSE_EXPORTER
|
WSF_RESPONSE_EXPORTER
|
||||||
|
|
||||||
WGI_EXPORTER
|
WGI_EXPORTER
|
||||||
|
|
||||||
HTTPD_LOGGER_CONSTANTS
|
|
||||||
|
|
||||||
WEB_SOCKET_CONSTANTS
|
|
||||||
|
|
||||||
SHARED_BASE64
|
SHARED_BASE64
|
||||||
|
|
||||||
create
|
create
|
||||||
@@ -32,7 +30,7 @@ feature {NONE} -- Initialization
|
|||||||
request := req
|
request := req
|
||||||
response := res
|
response := res
|
||||||
is_verbose := False
|
is_verbose := False
|
||||||
verbose_level := notice_level
|
verbose_level := {HTTPD_LOGGER_CONSTANTS}.notice_level
|
||||||
|
|
||||||
if
|
if
|
||||||
attached {WGI_STANDALONE_INPUT_STREAM} req.input as r_input
|
attached {WGI_STANDALONE_INPUT_STREAM} req.input as r_input
|
||||||
@@ -44,11 +42,6 @@ feature {NONE} -- Initialization
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
socket: HTTPD_STREAM_SOCKET
|
|
||||||
-- Underlying connected socket.
|
|
||||||
|
|
||||||
feature {NONE} -- Access
|
feature {NONE} -- Access
|
||||||
|
|
||||||
request: WSF_REQUEST
|
request: WSF_REQUEST
|
||||||
@@ -75,14 +68,7 @@ feature -- Status
|
|||||||
has_error: BOOLEAN
|
has_error: BOOLEAN
|
||||||
-- Error occured during processing?
|
-- Error occured during processing?
|
||||||
|
|
||||||
feature -- Socket status
|
feature -- Status report
|
||||||
|
|
||||||
is_ready_for_reading: BOOLEAN
|
|
||||||
-- Is `socket' ready for reading?
|
|
||||||
--| at this point, socket should be set to blocking.
|
|
||||||
do
|
|
||||||
Result := socket.ready_for_reading
|
|
||||||
end
|
|
||||||
|
|
||||||
is_open_read: BOOLEAN
|
is_open_read: BOOLEAN
|
||||||
-- Is `socket' open for reading?
|
-- Is `socket' open for reading?
|
||||||
@@ -96,12 +82,6 @@ feature -- Socket status
|
|||||||
Result := socket.is_open_write
|
Result := socket.is_open_write
|
||||||
end
|
end
|
||||||
|
|
||||||
socket_descriptor: INTEGER
|
|
||||||
-- Descriptor for current `socket'.
|
|
||||||
do
|
|
||||||
Result := socket.descriptor
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Element change
|
feature -- Element change
|
||||||
|
|
||||||
set_is_verbose (b: BOOLEAN)
|
set_is_verbose (b: BOOLEAN)
|
||||||
@@ -129,7 +109,7 @@ feature -- Basic operation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Basic Operation
|
feature {WSF_WEBSOCKET_EXECUTION} -- Basic Operation
|
||||||
|
|
||||||
open_ws_handshake
|
open_ws_handshake
|
||||||
-- The opening handshake is intended to be compatible with HTTP-based
|
-- The opening handshake is intended to be compatible with HTTP-based
|
||||||
@@ -164,10 +144,10 @@ feature -- Basic Operation
|
|||||||
|
|
||||||
-- TODO extract to a validator handshake or something like that.
|
-- TODO extract to a validator handshake or something like that.
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("%NReceive <====================", debug_level)
|
log ("%NReceive <====================", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
if attached req.raw_header_data as rhd then
|
if attached req.raw_header_data as rhd then
|
||||||
check raw_header_is_valid_as_string_8: rhd.is_valid_as_string_8 end
|
check raw_header_is_valid_as_string_8: rhd.is_valid_as_string_8 end
|
||||||
log (rhd.to_string_8, debug_level)
|
log (rhd.to_string_8, {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if
|
if
|
||||||
@@ -186,7 +166,7 @@ feature -- Basic Operation
|
|||||||
attached req.http_host -- Host header must be present
|
attached req.http_host -- Host header must be present
|
||||||
then
|
then
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("key " + l_ws_key, debug_level)
|
log ("key " + l_ws_key, {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
-- Sending the server's opening handshake
|
-- Sending the server's opening handshake
|
||||||
create l_sha1.make
|
create l_sha1.make
|
||||||
@@ -198,9 +178,9 @@ feature -- Basic Operation
|
|||||||
res.header.add_header_key_value ("Sec-WebSocket-Accept", l_key)
|
res.header.add_header_key_value ("Sec-WebSocket-Accept", l_key)
|
||||||
|
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("%N================> Send Handshake", debug_level)
|
log ("%N================> Send Handshake", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
if attached {HTTP_HEADER} res.header as h then
|
if attached {HTTP_HEADER} res.header as h then
|
||||||
log (h.string, debug_level)
|
log (h.string, {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
res.set_status_code_with_reason_phrase (101, "Switching Protocols")
|
res.set_status_code_with_reason_phrase (101, "Switching Protocols")
|
||||||
@@ -208,7 +188,7 @@ feature -- Basic Operation
|
|||||||
else
|
else
|
||||||
has_error := True
|
has_error := True
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("Error (opening_handshake)!!!", debug_level)
|
log ("Error (opening_handshake)!!!", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
-- If we cannot complete the handshake, then the server MUST stop processing the client's handshake and return an HTTP response with an
|
-- If we cannot complete the handshake, then the server MUST stop processing the client's handshake and return an HTTP response with an
|
||||||
-- appropriate error code (such as 400 Bad Request).
|
-- appropriate error code (such as 400 Bad Request).
|
||||||
@@ -219,80 +199,77 @@ feature -- Basic Operation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Response!
|
feature {WEB_SOCKET_HANDLER} -- Networking
|
||||||
|
|
||||||
send (a_opcode:INTEGER; a_message: READABLE_STRING_8)
|
socket: HTTPD_STREAM_SOCKET
|
||||||
|
-- Underlying connected socket.
|
||||||
|
|
||||||
|
has_input: BOOLEAN
|
||||||
|
-- Set by `wait_for_input`.
|
||||||
|
|
||||||
|
wait_for_input (cb: detachable WEB_SOCKET_EVENT_I)
|
||||||
local
|
local
|
||||||
i: INTEGER
|
l_timeout, nb: INTEGER
|
||||||
l_chunk_size: INTEGER
|
l_cb_timeout: INTEGER
|
||||||
l_chunk: READABLE_STRING_8
|
|
||||||
l_header_message: STRING
|
|
||||||
l_message_count: INTEGER
|
|
||||||
n: NATURAL_64
|
|
||||||
retried: BOOLEAN
|
|
||||||
do
|
do
|
||||||
debug ("ws")
|
has_input := False
|
||||||
print (">>do_send (..., "+ opcode_name (a_opcode) +", ..)%N")
|
if cb = Void then
|
||||||
end
|
has_input := socket.ready_for_reading
|
||||||
if not retried then
|
else
|
||||||
create l_header_message.make_empty
|
l_cb_timeout := cb.timer_delay
|
||||||
l_header_message.append_code ((0x80 | a_opcode).to_natural_32)
|
l_timeout := socket.timeout
|
||||||
l_message_count := a_message.count
|
if l_cb_timeout = 0 then
|
||||||
n := l_message_count.to_natural_64
|
-- timeout event not enabled.
|
||||||
if l_message_count > 0xffff then
|
has_input := socket.ready_for_reading
|
||||||
--! Improve. this code needs to be checked.
|
|
||||||
l_header_message.append_code ((0 | 127).to_natural_32)
|
|
||||||
l_header_message.append_character ((n |>> 56).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 48).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 40).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 32).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 24).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 16).to_character_8)
|
|
||||||
l_header_message.append_character ((n |>> 8).to_character_8)
|
|
||||||
l_header_message.append_character ( n.to_character_8)
|
|
||||||
elseif l_message_count > 125 then
|
|
||||||
l_header_message.append_code ((0 | 126).to_natural_32)
|
|
||||||
l_header_message.append_code ((n |>> 8).as_natural_32)
|
|
||||||
l_header_message.append_character (n.to_character_8)
|
|
||||||
else
|
else
|
||||||
l_header_message.append_code (n.as_natural_32)
|
cb.on_timer (Current)
|
||||||
end
|
if l_cb_timeout > l_timeout then
|
||||||
socket.put_string_8_noexception (l_header_message)
|
-- event timeout duration is bigger than socket timeout
|
||||||
if not socket.was_error then
|
-- thus, no on_timeout before next frame waiting
|
||||||
l_chunk_size := 16_384 -- 16K TODO: see if we should make it customizable.
|
has_input := socket.ready_for_reading
|
||||||
if l_message_count < l_chunk_size then
|
|
||||||
socket.put_string_8_noexception (a_message)
|
|
||||||
else
|
else
|
||||||
from
|
from
|
||||||
i := 0
|
l_timeout := socket.timeout
|
||||||
|
nb := l_timeout
|
||||||
|
socket.set_timeout (l_cb_timeout) -- FIXME: for now 1 sec is the smaller timeout we can use.
|
||||||
until
|
until
|
||||||
l_chunk_size = 0 or socket.was_error
|
has_input or nb <= 0
|
||||||
loop
|
loop
|
||||||
debug ("ws")
|
has_input := socket.ready_for_reading
|
||||||
print ("Sending chunk " + (i + 1).out + " -> " + (i + l_chunk_size).out +" / " + l_message_count.out + "%N")
|
if not has_input then
|
||||||
|
-- Call on_timeout only if there is no input,
|
||||||
|
-- otherwise it was called once before the initial wait.
|
||||||
|
socket.set_timeout (l_timeout)
|
||||||
|
cb.on_timer (Current)
|
||||||
|
socket.set_timeout (l_cb_timeout)
|
||||||
end
|
end
|
||||||
l_chunk := a_message.substring (i + 1, l_message_count.min (i + l_chunk_size))
|
nb := nb - l_cb_timeout
|
||||||
socket.put_string_8_noexception (l_chunk)
|
|
||||||
if l_chunk.count < l_chunk_size then
|
|
||||||
l_chunk_size := 0
|
|
||||||
end
|
|
||||||
i := i + l_chunk_size
|
|
||||||
end
|
|
||||||
debug ("ws")
|
|
||||||
print ("Sending chunk done%N")
|
|
||||||
end
|
end
|
||||||
|
socket.set_timeout (l_timeout)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
|
||||||
-- FIXME: what should be done on rescue?
|
|
||||||
end
|
end
|
||||||
rescue
|
|
||||||
retried := True
|
|
||||||
io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", a_message) !%N")
|
|
||||||
retry
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
socket_descriptor: INTEGER
|
||||||
|
-- Descriptor for current `socket'.
|
||||||
|
do
|
||||||
|
Result := socket.descriptor
|
||||||
|
end
|
||||||
|
|
||||||
|
socket_put_string (s: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
socket.put_string_8_noexception (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
socket_was_error: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := socket.was_error
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {WEB_SOCKET_HANDLER} -- Frame
|
||||||
|
|
||||||
next_frame: detachable WEB_SOCKET_FRAME
|
next_frame: detachable WEB_SOCKET_FRAME
|
||||||
-- TODO Binary messages
|
-- TODO Binary messages
|
||||||
-- Handle error responses in a better way.
|
-- Handle error responses in a better way.
|
||||||
@@ -402,7 +379,7 @@ feature -- Response!
|
|||||||
if Result.is_valid then
|
if Result.is_valid then
|
||||||
--| valid frame/fragment
|
--| valid frame/fragment
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("+ frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", debug_level)
|
log ("+ frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- rsv validation
|
-- rsv validation
|
||||||
@@ -420,7 +397,7 @@ feature -- Response!
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("+ INVALID frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", debug_level)
|
log ("+ INVALID frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -548,7 +525,7 @@ feature -- Response!
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log (" Received " + l_fetch_count.out + " out of " + l_len.out + " bytes <===============", debug_level)
|
log (" Received " + l_fetch_count.out + " out of " + l_len.out + " bytes <===============", {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
debug ("ws")
|
debug ("ws")
|
||||||
print (" -> ")
|
print (" -> ")
|
||||||
@@ -580,7 +557,7 @@ feature -- Response!
|
|||||||
if Result /= Void then
|
if Result /= Void then
|
||||||
if attached Result.error as err then
|
if attached Result.error as err then
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log (" !Invalid frame: " + err.string, debug_level)
|
log (" !Invalid frame: " + err.string, {HTTPD_LOGGER_CONSTANTS}.debug_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Result.is_injected_control then
|
if Result.is_injected_control then
|
||||||
@@ -624,8 +601,7 @@ feature -- Response!
|
|||||||
retry
|
retry
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Encoding
|
||||||
feature -- Encoding
|
|
||||||
|
|
||||||
digest (a_sha1: SHA1): STRING
|
digest (a_sha1: SHA1): STRING
|
||||||
-- Digest of `a_sha1'.
|
-- Digest of `a_sha1'.
|
||||||
@@ -672,7 +648,7 @@ feature {NONE} -- Socket helpers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Masking Data Client - Server
|
feature {NONE} -- Masking Data Client - Server
|
||||||
|
|
||||||
unmask (a_chunk: STRING_8; a_pos: INTEGER; a_key: READABLE_STRING_8)
|
unmask (a_chunk: STRING_8; a_pos: INTEGER; a_key: READABLE_STRING_8)
|
||||||
local
|
local
|
||||||
@@ -795,7 +771,6 @@ feature {NONE} -- Debug
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ feature -- Execution
|
|||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
dbglog (generator + ".execute_websocket (loop) WS_REQUEST_HANDLER.process_request {" + ws.socket_descriptor.out + "}")
|
dbglog (generator + ".execute_websocket (loop) WS_REQUEST_HANDLER.process_request {" + ws.socket_descriptor.out + "}")
|
||||||
end
|
end
|
||||||
if ws.is_ready_for_reading then
|
ws.wait_for_input (callbacks)
|
||||||
|
if ws.has_input then
|
||||||
l_frame := ws.next_frame
|
l_frame := ws.next_frame
|
||||||
if l_frame /= Void and then l_frame.is_valid then
|
if l_frame /= Void and then l_frame.is_valid then
|
||||||
if attached l_frame.injected_control_frames as l_injections then
|
if attached l_frame.injected_control_frames as l_injections then
|
||||||
@@ -140,7 +141,7 @@ feature {NONE} -- Logging
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WEB_SOCKET_WRITER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WEB_SOCKET_WRITER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WEB_SOCKET_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Messages
|
||||||
|
|
||||||
|
send_text (a_message: READABLE_STRING_8)
|
||||||
|
-- Send text frame `a_message`.
|
||||||
|
do
|
||||||
|
send (text_frame, a_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
send_connection_close (a_message: detachable READABLE_STRING_8)
|
||||||
|
-- Send connection close frame `a_message`.
|
||||||
|
do
|
||||||
|
send (connection_close_frame, a_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
send_binary (a_data: READABLE_STRING_8)
|
||||||
|
-- Send binary frame `a_data`.
|
||||||
|
do
|
||||||
|
send (Binary_frame, a_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Custom Message
|
||||||
|
|
||||||
|
send (a_opcode: INTEGER; a_message: detachable READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
i: INTEGER
|
||||||
|
l_chunk_size: INTEGER
|
||||||
|
l_chunk: READABLE_STRING_8
|
||||||
|
l_header_message: STRING
|
||||||
|
l_message_count: INTEGER
|
||||||
|
n: NATURAL_64
|
||||||
|
retried: BOOLEAN
|
||||||
|
do
|
||||||
|
debug ("ws")
|
||||||
|
print (">>do_send (..., "+ opcode_name (a_opcode) +", ..)%N")
|
||||||
|
end
|
||||||
|
if not retried then
|
||||||
|
create l_header_message.make_empty
|
||||||
|
l_header_message.append_code ((0x80 | a_opcode).to_natural_32)
|
||||||
|
if a_message /= Void then
|
||||||
|
l_message_count := a_message.count
|
||||||
|
else
|
||||||
|
l_message_count := 0
|
||||||
|
end
|
||||||
|
n := l_message_count.to_natural_64
|
||||||
|
if l_message_count > 0xffff then
|
||||||
|
--! Improve. this code needs to be checked.
|
||||||
|
l_header_message.append_code ((0 | 127).to_natural_32)
|
||||||
|
l_header_message.append_character ((n |>> 56).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 48).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 40).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 32).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 24).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 16).to_character_8)
|
||||||
|
l_header_message.append_character ((n |>> 8).to_character_8)
|
||||||
|
l_header_message.append_character ( n.to_character_8)
|
||||||
|
elseif l_message_count > 125 then
|
||||||
|
l_header_message.append_code ((0 | 126).to_natural_32)
|
||||||
|
l_header_message.append_code ((n |>> 8).as_natural_32)
|
||||||
|
l_header_message.append_character (n.to_character_8)
|
||||||
|
else
|
||||||
|
l_header_message.append_code (n.as_natural_32)
|
||||||
|
end
|
||||||
|
socket_put_string (l_header_message)
|
||||||
|
if not socket_was_error then
|
||||||
|
l_chunk_size := 16_384 -- 16K TODO: see if we should make it customizable.
|
||||||
|
if a_message = Void or else l_message_count < l_chunk_size then
|
||||||
|
if a_message /= Void then
|
||||||
|
socket_put_string (a_message)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
from
|
||||||
|
i := 0
|
||||||
|
until
|
||||||
|
l_chunk_size = 0 or socket_was_error
|
||||||
|
loop
|
||||||
|
debug ("ws")
|
||||||
|
print ("Sending chunk " + (i + 1).out + " -> " + (i + l_chunk_size).out +" / " + l_message_count.out + "%N")
|
||||||
|
end
|
||||||
|
l_chunk := a_message.substring (i + 1, l_message_count.min (i + l_chunk_size))
|
||||||
|
socket_put_string (l_chunk)
|
||||||
|
if l_chunk.count < l_chunk_size then
|
||||||
|
l_chunk_size := 0
|
||||||
|
end
|
||||||
|
i := i + l_chunk_size
|
||||||
|
end
|
||||||
|
debug ("ws")
|
||||||
|
print ("Sending chunk done%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- FIXME: what should be done on rescue?
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
retried := True
|
||||||
|
io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", a_message) !%N")
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Networking
|
||||||
|
|
||||||
|
socket_put_string (s: READABLE_STRING_8)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
socket_was_error: BOOLEAN
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, 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
|
||||||
237
library/server/wsf/extension/handler/cgi/wsf_cgi_handler.e
Normal file
237
library/server/wsf/extension/handler/cgi/wsf_cgi_handler.e
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
note
|
||||||
|
description: "Handler to process CGI script."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_CGI_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make (a_dir: PATH)
|
||||||
|
do
|
||||||
|
working_direction := a_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Settings
|
||||||
|
|
||||||
|
buffer_size: INTEGER = 1_024
|
||||||
|
|
||||||
|
working_direction: PATH
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
cgi_file_path (req: WSF_REQUEST): PATH
|
||||||
|
local
|
||||||
|
l_path_info: READABLE_STRING_32
|
||||||
|
do
|
||||||
|
-- Path to CGI executable.
|
||||||
|
l_path_info := req.path_info
|
||||||
|
if l_path_info.starts_with_general ("/") then
|
||||||
|
l_path_info := l_path_info.substring (2, l_path_info.count)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Process
|
||||||
|
Result := working_direction.extended (l_path_info)
|
||||||
|
end
|
||||||
|
|
||||||
|
exists (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- CGI file exists?
|
||||||
|
do
|
||||||
|
Result := (create {FILE_UTILITIES}).file_path_exists (cgi_file_path (req))
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute `req' responding in `res'.
|
||||||
|
local
|
||||||
|
fut: FILE_UTILITIES
|
||||||
|
l_exec_path: PATH
|
||||||
|
proc: BASE_PROCESS
|
||||||
|
l_input_env: STRING_TABLE [READABLE_STRING_GENERAL]
|
||||||
|
l_input_header: detachable STRING
|
||||||
|
l_input_buf: STRING
|
||||||
|
l_output: STRING
|
||||||
|
l_output_header_sent: BOOLEAN
|
||||||
|
l_error: STRING
|
||||||
|
s: STRING
|
||||||
|
i, j, n: INTEGER
|
||||||
|
do
|
||||||
|
-- Header
|
||||||
|
if attached req.raw_header_data as l_header then
|
||||||
|
l_input_header := l_header
|
||||||
|
end
|
||||||
|
-- Input data
|
||||||
|
create l_input_buf.make (req.content_length_value.to_integer_32)
|
||||||
|
req.read_input_data_into (l_input_buf)
|
||||||
|
|
||||||
|
-- Input environment
|
||||||
|
create l_input_env.make (10)
|
||||||
|
across
|
||||||
|
req.meta_variables as ic
|
||||||
|
loop
|
||||||
|
if attached {WSF_STRING} ic.item as var then
|
||||||
|
l_input_env.force (var.value, var.name)
|
||||||
|
else
|
||||||
|
check supported: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- No need to import `l_input_header` in environment
|
||||||
|
-- As current connector already did the job.
|
||||||
|
|
||||||
|
-- Process
|
||||||
|
l_exec_path := cgi_file_path (req)
|
||||||
|
if fut.file_path_exists (l_exec_path) then
|
||||||
|
proc := (create {BASE_PROCESS_FACTORY}).process_launcher (l_exec_path.name, Void, working_direction.name)
|
||||||
|
proc.set_hidden (True)
|
||||||
|
proc.set_environment_variable_table (l_input_env)
|
||||||
|
proc.set_separate_console (False)
|
||||||
|
proc.redirect_input_to_stream
|
||||||
|
proc.redirect_output_to_stream
|
||||||
|
proc.redirect_error_to_stream
|
||||||
|
|
||||||
|
-- Launch CGI execution
|
||||||
|
proc.launch
|
||||||
|
if proc.launched then
|
||||||
|
-- Do not send the header to CGI script
|
||||||
|
-- value are passed via environment variables
|
||||||
|
-- proc.put_string (l_input_header)
|
||||||
|
-- Send payload.
|
||||||
|
proc.put_string (l_input_buf)
|
||||||
|
|
||||||
|
create l_output.make_empty
|
||||||
|
create l_error.make_empty
|
||||||
|
get_output_and_error_from_process (proc, l_output, l_error)
|
||||||
|
if l_error /= Void and then not l_error.is_whitespace then
|
||||||
|
res.put_error (l_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wait for process exit
|
||||||
|
if not proc.has_exited then
|
||||||
|
proc.wait_for_exit
|
||||||
|
end
|
||||||
|
if proc.exit_code /= 0 then
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||||
|
s := "CGI script execution failed [exit code=" + proc.exit_code.out+ "]!"
|
||||||
|
res.header.put_content_type_utf_8_text_plain
|
||||||
|
res.header.put_content_length (s.count)
|
||||||
|
res.put_string (s)
|
||||||
|
else
|
||||||
|
-- Send the response
|
||||||
|
-- error already sent via `res.put_error (l_error)`
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := l_output.count
|
||||||
|
until
|
||||||
|
i > n or l_output_header_sent
|
||||||
|
loop
|
||||||
|
j := l_output.index_of ('%N', i)
|
||||||
|
if j > 0 then
|
||||||
|
s := l_output.substring (i, j)
|
||||||
|
s.right_adjust
|
||||||
|
if s.is_empty then
|
||||||
|
-- Reached end of header
|
||||||
|
l_output_header_sent := True
|
||||||
|
else
|
||||||
|
res.add_header_line (s)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- ERROR
|
||||||
|
l_output_header_sent := True
|
||||||
|
end
|
||||||
|
i := j + 1
|
||||||
|
end
|
||||||
|
if l_output_header_sent then
|
||||||
|
if i <= n then
|
||||||
|
res.put_string (l_output.substring (i, n))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||||
|
s := "Internal server error!"
|
||||||
|
res.header.put_content_type_utf_8_text_plain
|
||||||
|
res.header.put_content_length (s.count)
|
||||||
|
res.put_string (s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
|
||||||
|
s := "Could not launch CGI script!"
|
||||||
|
res.header.put_content_type_utf_8_text_plain
|
||||||
|
res.header.put_content_length (s.count)
|
||||||
|
res.put_string (s)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.not_found)
|
||||||
|
s := "Not found!"
|
||||||
|
res.header.put_content_type_utf_8_text_plain
|
||||||
|
res.header.put_content_length (s.count)
|
||||||
|
res.put_string (s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get_output_and_error_from_process (proc: BASE_PROCESS; a_output: STRING; a_error: STRING)
|
||||||
|
local
|
||||||
|
output_buf, error_buf: SPECIAL [NATURAL_8]
|
||||||
|
do
|
||||||
|
from
|
||||||
|
create output_buf.make_filled (0, buffer_size)
|
||||||
|
create error_buf.make_filled (0, buffer_size)
|
||||||
|
until
|
||||||
|
not attached output_buf and not attached error_buf
|
||||||
|
loop
|
||||||
|
if attached output_buf then
|
||||||
|
if proc.has_output_stream_error or proc.has_output_stream_closed then
|
||||||
|
output_buf := Void
|
||||||
|
end
|
||||||
|
if attached output_buf then
|
||||||
|
-- Try reading from standard output.
|
||||||
|
proc.read_output_to_special (output_buf)
|
||||||
|
across
|
||||||
|
output_buf as ic
|
||||||
|
loop
|
||||||
|
a_output.append_code (ic.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if attached output_buf implies output_buf.count = 0 and then attached error_buf then
|
||||||
|
-- Nothing is read from standard output, switch to standard error.
|
||||||
|
if proc.has_error_stream_error or proc.has_error_stream_closed then
|
||||||
|
error_buf := Void
|
||||||
|
end
|
||||||
|
if attached error_buf then
|
||||||
|
-- Try reading from standard error.
|
||||||
|
proc.read_error_to_special (error_buf)
|
||||||
|
across
|
||||||
|
error_buf as ic
|
||||||
|
loop
|
||||||
|
a_error.append_code (ic.item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if attached output_buf then
|
||||||
|
output_buf.extend_filled (0)
|
||||||
|
end
|
||||||
|
if attached error_buf then
|
||||||
|
error_buf.extend_filled (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -221,17 +221,19 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
|
|
||||||
l_url := Void
|
l_url := Void
|
||||||
s.append ("<li>")
|
s.append ("<li>")
|
||||||
s.append ("<code>")
|
if attached m.associated_resource as l_associated_resource then
|
||||||
if doc_url_supported then
|
s.append ("<code>")
|
||||||
s.append ("<a class=%"mappingresource%" href=%"")
|
if doc_url_supported then
|
||||||
s.append (doc_url (m.associated_resource))
|
s.append ("<a class=%"mappingresource%" href=%"")
|
||||||
s.append ("%">")
|
s.append (doc_url (l_associated_resource))
|
||||||
s.append (m.associated_resource)
|
s.append ("%">")
|
||||||
s.append ("</a>")
|
s.append (l_associated_resource)
|
||||||
else
|
s.append ("</a>")
|
||||||
s.append (m.associated_resource)
|
else
|
||||||
|
s.append (l_associated_resource)
|
||||||
|
end
|
||||||
|
s.append ("</code>")
|
||||||
end
|
end
|
||||||
s.append ("</code>")
|
|
||||||
|
|
||||||
if meths /= Void then
|
if meths /= Void then
|
||||||
s.append (" [")
|
s.append (" [")
|
||||||
@@ -291,7 +293,11 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
s.append ("</li>%N")
|
s.append ("</li>%N")
|
||||||
else
|
else
|
||||||
debug
|
debug
|
||||||
s.append ("<li>" + m.associated_resource + " is HIDDEN</li>%N")
|
if attached m.associated_resource as l_associated_resource then
|
||||||
|
s.append ("<li>" + l_associated_resource + " is HIDDEN</li>%N")
|
||||||
|
else
|
||||||
|
s.append ("<li>HIDDEN</li>%N")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_ROUTING_AGENT_CONDITION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_AGENT_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (act: like condition)
|
||||||
|
do
|
||||||
|
condition := act
|
||||||
|
end
|
||||||
|
|
||||||
|
condition: FUNCTION [TUPLE [request: WSF_REQUEST], BOOLEAN]
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
do
|
||||||
|
Result := condition (req)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Request path info ends with one of the specified extensions.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_EXTENSION_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make (a_extension_list: ITERABLE [READABLE_STRING_GENERAL])
|
||||||
|
do
|
||||||
|
extension_list := a_extension_list
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
extension_list: ITERABLE [READABLE_STRING_GENERAL]
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
local
|
||||||
|
l_path: READABLE_STRING_GENERAL
|
||||||
|
i: INTEGER
|
||||||
|
do
|
||||||
|
l_path := req.percent_encoded_path_info
|
||||||
|
i := l_path.last_index_of ('.', l_path.count)
|
||||||
|
if i > 0 then
|
||||||
|
i := i + 1
|
||||||
|
Result := across extension_list as ic some ic.item.same_caseless_characters (l_path, i, l_path.count, 1) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Request path info is associated with existing file.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_FILE_EXISTS_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_PATH_EXISTS_CONDITION
|
||||||
|
redefine
|
||||||
|
path_exists
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
path_exists (p: PATH): BOOLEAN
|
||||||
|
local
|
||||||
|
fut: FILE_UTILITIES
|
||||||
|
do
|
||||||
|
Result := fut.file_path_exists (p)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Request path info is associated with existing file or folder.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_PATH_EXISTS_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make (a_parent_location: PATH)
|
||||||
|
do
|
||||||
|
parent_location := a_parent_location
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
parent_location: PATH
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
path_exists (p: PATH): BOOLEAN
|
||||||
|
local
|
||||||
|
fut: FILE_UTILITIES
|
||||||
|
do
|
||||||
|
Result := fut.file_path_exists (p) or fut.directory_path_exists (p)
|
||||||
|
end
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
local
|
||||||
|
l_path: READABLE_STRING_GENERAL
|
||||||
|
p: PATH
|
||||||
|
do
|
||||||
|
l_path := req.path_info
|
||||||
|
if not l_path.is_empty then
|
||||||
|
if l_path[1] = '/' then
|
||||||
|
l_path := l_path.substring (2, l_path.count)
|
||||||
|
end
|
||||||
|
p := parent_location.extended (l_path)
|
||||||
|
Result := path_exists (p)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_ROUTING_AND_CONDITION}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_AND_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make (a_left, a_right: WSF_ROUTING_CONDITION)
|
||||||
|
do
|
||||||
|
left := a_left
|
||||||
|
right := a_right
|
||||||
|
end
|
||||||
|
|
||||||
|
left, right: WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
do
|
||||||
|
Result := left.accepted (req) and then right.accepted (req)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_ROUTING_CONDITION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Factory
|
||||||
|
|
||||||
|
conjuncted alias "and" (cond: WSF_ROUTING_CONDITION): WSF_ROUTING_AND_CONDITION
|
||||||
|
do
|
||||||
|
create Result.make (Current, cond)
|
||||||
|
end
|
||||||
|
|
||||||
|
disjuncted alias "or" (cond: WSF_ROUTING_CONDITION): WSF_ROUTING_OR_CONDITION
|
||||||
|
do
|
||||||
|
create Result.make (Current, cond)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_ROUTING_OR_CONDITION}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_ROUTING_OR_CONDITION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make (a_left, a_right: WSF_ROUTING_CONDITION)
|
||||||
|
do
|
||||||
|
left := a_left
|
||||||
|
right := a_right
|
||||||
|
end
|
||||||
|
|
||||||
|
left, right: WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
accepted (req: WSF_REQUEST): BOOLEAN
|
||||||
|
-- Does `req` satisfy Current condition?
|
||||||
|
do
|
||||||
|
Result := left.accepted (req) or else right.accepted (req)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_WITH_CONDITION_HANDLER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_WITH_CONDITION_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for WSF_WITH_CONDITION_MAPPING."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_WITH_CONDITION_MAPPING
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_WITH_CONDITION_MAPPING_I
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
handler: WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
feature -- change
|
||||||
|
|
||||||
|
set_handler (h: like handler)
|
||||||
|
do
|
||||||
|
handler := h
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Execution
|
||||||
|
|
||||||
|
execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute handler `h' with `req' and `res' for Current mapping
|
||||||
|
do
|
||||||
|
h.execute (req, res)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for WSF_WITH_CONDITION_MAPPING_I."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_WITH_CONDITION_MAPPING_I
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTER_MAPPING
|
||||||
|
|
||||||
|
WSF_SELF_DOCUMENTED_ROUTER_MAPPING
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_condition: like condition; h: like handler)
|
||||||
|
do
|
||||||
|
set_handler (h)
|
||||||
|
condition := a_condition
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
condition: WSF_ROUTING_CONDITION
|
||||||
|
|
||||||
|
associated_resource: READABLE_STRING_8
|
||||||
|
-- Name (URI, or URI template or regular expression or ...) of handled resource
|
||||||
|
do
|
||||||
|
if attached condition_description as desc and then desc.is_valid_as_string_8 then
|
||||||
|
Result := desc.to_string_8
|
||||||
|
else
|
||||||
|
Result := description
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
condition_description: detachable READABLE_STRING_32
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_condition_description (desc: detachable READABLE_STRING_GENERAL)
|
||||||
|
do
|
||||||
|
if desc = Void then
|
||||||
|
condition_description := Void
|
||||||
|
else
|
||||||
|
condition_description := desc.as_string_32
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_handler (h: like handler)
|
||||||
|
-- Set `handler' to `h'.
|
||||||
|
require
|
||||||
|
h_attached: h /= Void
|
||||||
|
deferred
|
||||||
|
ensure
|
||||||
|
h_aliased: handler = h
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Documentation
|
||||||
|
|
||||||
|
description: STRING_32 = "With-Condition"
|
||||||
|
|
||||||
|
feature -- Status
|
||||||
|
|
||||||
|
is_mapping (a_path: READABLE_STRING_8; req: WSF_REQUEST; a_router: WSF_ROUTER): BOOLEAN
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := condition.accepted (req)
|
||||||
|
end
|
||||||
|
|
||||||
|
try (a_path: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE; sess: WSF_ROUTER_SESSION; a_router: WSF_ROUTER)
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
if condition.accepted (req) then
|
||||||
|
sess.set_dispatched_handler (handler)
|
||||||
|
a_router.execute_before (Current)
|
||||||
|
execute_handler (handler, req, res)
|
||||||
|
a_router.execute_after (Current)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Execution
|
||||||
|
|
||||||
|
execute_handler (h: like handler; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute handler `h' with `req' and `res' for Current mapping.
|
||||||
|
require
|
||||||
|
h_attached: h /= Void
|
||||||
|
req_attached: req /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
path_validate_condition: condition.accepted (req)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
invariant
|
||||||
|
|
||||||
|
condition_attached: condition /= Void
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_EXECUTE_AGENT_HANDLER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_EXECUTE_AGENT_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_HANDLER
|
||||||
|
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_action: like action)
|
||||||
|
do
|
||||||
|
action := a_action
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
action: PROCEDURE [TUPLE [request: WSF_REQUEST; response: WSF_RESPONSE]]
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
action (req, res)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Handler that can also play the role of a filter, i.e.
|
||||||
|
than can pre-process incoming data and post-process outgoing data.
|
||||||
|
]"
|
||||||
|
author: "$Author$"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_EXECUTE_FILTER_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_FILTER_HANDLER [WSF_EXECUTE_HANDLER]
|
||||||
|
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute_next (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
if attached next as n then
|
||||||
|
n.execute (req, res)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_EXECUTE_RESPONSE_AGENT_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_EXECUTE_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTE_RESPONSE_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Initialization
|
||||||
|
|
||||||
|
make (act: like action)
|
||||||
|
do
|
||||||
|
action := act
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
action: FUNCTION [TUPLE [req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||||
|
do
|
||||||
|
Result := action.item ([req])
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_EXECUTE_RESPONSE_HANDLER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_EXECUTE_RESPONSE_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
feature -- Response
|
||||||
|
|
||||||
|
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
||||||
|
require
|
||||||
|
is_valid_context: is_valid_context (req)
|
||||||
|
deferred
|
||||||
|
ensure
|
||||||
|
Result_attached: Result /= Void
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute request handler
|
||||||
|
do
|
||||||
|
res.send (response (req))
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_EXECUTE_ROUTING_HANDLER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_EXECUTE_ROUTING_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTING_HANDLER
|
||||||
|
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {WSF_SELF_DOCUMENTED_EXECUTE_AGENT_HANDLER}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_SELF_DOCUMENTED_EXECUTE_AGENT_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTE_AGENT_HANDLER
|
||||||
|
rename
|
||||||
|
make as make_handler
|
||||||
|
end
|
||||||
|
|
||||||
|
WSF_SELF_DOCUMENTED_AGENT_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make,
|
||||||
|
make_with_descriptions,
|
||||||
|
make_hidden
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_action: like action; a_self_doc: like self_documentation_builder)
|
||||||
|
-- <Precursor>
|
||||||
|
-- and using `a_self_doc' function to build the `mapping_documentation'.
|
||||||
|
do
|
||||||
|
set_self_documentation_builder (a_self_doc)
|
||||||
|
make_handler (a_action)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_descriptions (a_action: like action; a_descriptions: ITERABLE [READABLE_STRING_GENERAL])
|
||||||
|
do
|
||||||
|
across
|
||||||
|
a_descriptions as c
|
||||||
|
loop
|
||||||
|
add_description (c.item)
|
||||||
|
end
|
||||||
|
make_handler (a_action)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_hidden (a_action: like action)
|
||||||
|
-- <Precursor>
|
||||||
|
-- and using `a_self_doc' function to build the `mapping_documentation'
|
||||||
|
-- mark it as `hidden'.
|
||||||
|
do
|
||||||
|
is_hidden := True
|
||||||
|
make (a_action, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Represents the ancestor of all the WSF_ROUTER handlers with `execute (WSF_REQUEST, WSF_RESPONSE)` routine.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_EXECUTE_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_HANDLER
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute `req' responding in `res'.
|
||||||
|
require
|
||||||
|
req_attached: req /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {WSF_SELF_DOCUMENTED_URI_AGENT_HANDLER}."
|
description: "Summary description for {WSF_SELF_DOCUMENTED_URI_AGENT_HANDLER}."
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ feature {NONE} -- Initialization
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,31 +8,14 @@ class
|
|||||||
WSF_URI_AGENT_HANDLER
|
WSF_URI_AGENT_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_EXECUTE_AGENT_HANDLER
|
||||||
WSF_URI_HANDLER
|
WSF_URI_HANDLER
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make (a_action: like action)
|
|
||||||
do
|
|
||||||
action := a_action
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
action: PROCEDURE [TUPLE [request: WSF_REQUEST; response: WSF_RESPONSE]]
|
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
|
||||||
do
|
|
||||||
action.call ([req, res])
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,31 +8,17 @@ class
|
|||||||
WSF_URI_RESPONSE_AGENT_HANDLER
|
WSF_URI_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
WSF_URI_RESPONSE_HANDLER
|
WSF_EXECUTE_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
|
WSF_URI_RESPONSE_HANDLER
|
||||||
|
undefine
|
||||||
|
execute
|
||||||
|
end
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature -- Initialization
|
|
||||||
|
|
||||||
make (act: like action)
|
|
||||||
do
|
|
||||||
action := act
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
action: FUNCTION [TUPLE [req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]
|
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
|
||||||
do
|
|
||||||
Result := action.item ([req])
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ deferred class
|
|||||||
WSF_URI_RESPONSE_HANDLER
|
WSF_URI_RESPONSE_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_HANDLER
|
||||||
|
|
||||||
WSF_URI_HANDLER
|
WSF_URI_HANDLER
|
||||||
|
|
||||||
feature -- Response
|
feature -- Response
|
||||||
@@ -29,7 +31,7 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ inherit
|
|||||||
feature -- Execution
|
feature -- Execution
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
-- Execute handler for `req' and respond in `res'.
|
-- Execute `req' responding in `res'.
|
||||||
require
|
require
|
||||||
req_attached: req /= Void
|
req_attached: req /= Void
|
||||||
res_attached: res /= Void
|
res_attached: res /= Void
|
||||||
@@ -30,7 +30,7 @@ feature {WSF_ROUTER} -- Mapping
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ class
|
|||||||
WSF_URI_TEMPLATE_AGENT_HANDLER
|
WSF_URI_TEMPLATE_AGENT_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_EXECUTE_AGENT_HANDLER
|
||||||
|
|
||||||
WSF_URI_TEMPLATE_HANDLER
|
WSF_URI_TEMPLATE_HANDLER
|
||||||
|
|
||||||
create
|
create
|
||||||
@@ -16,26 +18,8 @@ create
|
|||||||
convert
|
convert
|
||||||
make ({PROCEDURE [WSF_REQUEST, WSF_RESPONSE]})
|
make ({PROCEDURE [WSF_REQUEST, WSF_RESPONSE]})
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make (a_action: like action)
|
|
||||||
do
|
|
||||||
action := a_action
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
action: PROCEDURE [TUPLE [request: WSF_REQUEST; response: WSF_RESPONSE]]
|
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
|
||||||
do
|
|
||||||
action.call ([req, res])
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,31 +8,18 @@ class
|
|||||||
WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER
|
WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_EXECUTE_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||||
|
undefine
|
||||||
|
execute
|
||||||
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature -- Initialization
|
|
||||||
|
|
||||||
make (act: like action)
|
|
||||||
do
|
|
||||||
action := act
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
action: FUNCTION [TUPLE [req: WSF_REQUEST], WSF_RESPONSE_MESSAGE]
|
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE
|
|
||||||
do
|
|
||||||
Result := action.item ([req])
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ deferred class
|
|||||||
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
WSF_URI_TEMPLATE_RESPONSE_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_RESPONSE_HANDLER
|
||||||
|
|
||||||
WSF_URI_TEMPLATE_HANDLER
|
WSF_URI_TEMPLATE_HANDLER
|
||||||
|
|
||||||
feature -- Response
|
feature -- Response
|
||||||
@@ -29,7 +31,7 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ feature {WSF_ROUTER} -- Mapping
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
make_with_path (d: like document_root)
|
make_with_path (d: like document_root)
|
||||||
do
|
do
|
||||||
|
initialize
|
||||||
max_age := -1
|
max_age := -1
|
||||||
if d.is_empty then
|
if d.is_empty then
|
||||||
document_root := execution_environment.current_working_path
|
document_root := execution_environment.current_working_path
|
||||||
@@ -73,6 +74,11 @@ feature {NONE} -- Initialization
|
|||||||
is_hidden: BOOLEAN
|
is_hidden: BOOLEAN
|
||||||
-- Current mapped handler should be hidden from self documentation
|
-- Current mapped handler should be hidden from self documentation
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize Current handler.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Documentation
|
feature -- Documentation
|
||||||
|
|
||||||
mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION
|
mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION
|
||||||
@@ -97,7 +103,7 @@ feature -- Access
|
|||||||
-- Function to evaluate if a path is ignored or not during autoindex.
|
-- Function to evaluate if a path is ignored or not during autoindex.
|
||||||
-- If `index_ignores' is Void and `index_ignores_function' is Void, use default ignore rules.
|
-- If `index_ignores' is Void and `index_ignores_function' is Void, use default ignore rules.
|
||||||
|
|
||||||
directory_index: detachable ARRAY [READABLE_STRING_8]
|
directory_index: detachable ITERABLE [READABLE_STRING_GENERAL]
|
||||||
-- File serve if a directory index is requested.
|
-- File serve if a directory index is requested.
|
||||||
|
|
||||||
not_found_handler: detachable PROCEDURE [TUPLE [uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
not_found_handler: detachable PROCEDURE [TUPLE [uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE]]
|
||||||
@@ -124,7 +130,7 @@ feature -- Element change
|
|||||||
set_directory_index (idx: like directory_index)
|
set_directory_index (idx: like directory_index)
|
||||||
-- Set `directory_index' as `idx'
|
-- Set `directory_index' as `idx'
|
||||||
do
|
do
|
||||||
if idx = Void or else idx.is_empty then
|
if idx = Void then
|
||||||
directory_index := Void
|
directory_index := Void
|
||||||
else
|
else
|
||||||
directory_index := idx
|
directory_index := idx
|
||||||
@@ -211,7 +217,7 @@ feature -- Execution
|
|||||||
fn := resource_filename (uri)
|
fn := resource_filename (uri)
|
||||||
create f.make_with_path (fn)
|
create f.make_with_path (fn)
|
||||||
if f.exists then
|
if f.exists then
|
||||||
if f.is_readable then
|
if f.is_access_readable then
|
||||||
if f.is_directory then
|
if f.is_directory then
|
||||||
if index_disabled then
|
if index_disabled then
|
||||||
process_directory_index_disabled (uri, req, res)
|
process_directory_index_disabled (uri, req, res)
|
||||||
@@ -341,6 +347,8 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
process_file (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
process_file (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
require
|
||||||
|
f_valid: f.exists and then f.is_access_readable
|
||||||
do
|
do
|
||||||
if
|
if
|
||||||
attached req.meta_string_variable ("HTTP_IF_MODIFIED_SINCE") as s_if_modified_since and then
|
attached req.meta_string_variable ("HTTP_IF_MODIFIED_SINCE") as s_if_modified_since and then
|
||||||
@@ -355,6 +363,8 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
require
|
||||||
|
f_valid: f.exists and then f.is_access_readable
|
||||||
local
|
local
|
||||||
ext: READABLE_STRING_32
|
ext: READABLE_STRING_32
|
||||||
ct: detachable READABLE_STRING_8
|
ct: detachable READABLE_STRING_8
|
||||||
@@ -366,7 +376,7 @@ feature -- Execution
|
|||||||
if ct = Void then
|
if ct = Void then
|
||||||
ct := {HTTP_MIME_TYPES}.application_force_download
|
ct := {HTTP_MIME_TYPES}.application_force_download
|
||||||
end
|
end
|
||||||
create fres.make_with_content_type (ct, f.path.name)
|
create fres.make_with_content_type_and_path (ct, f.path)
|
||||||
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
|
|
||||||
-- cache control
|
-- cache control
|
||||||
|
|||||||
24
library/server/wsf/router/wsf_response_handler.e
Normal file
24
library/server/wsf/router/wsf_response_handler.e
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Represents the ancestor of all the WSF_ROUTER handler based on message response.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_RESPONSE_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_HANDLER
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -11,16 +11,6 @@ deferred class
|
|||||||
inherit
|
inherit
|
||||||
DEBUG_OUTPUT
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make (a_resource: READABLE_STRING_8; h: like handler)
|
|
||||||
-- Create mapping based on resource `a_resource' and handler `h'.
|
|
||||||
require
|
|
||||||
a_resource_attached: a_resource /= Void
|
|
||||||
h_attached: h /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
associated_resource: READABLE_STRING_8
|
associated_resource: READABLE_STRING_8
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ feature -- Element change
|
|||||||
feature -- Execution
|
feature -- Execution
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
-- Execute request handler
|
-- Execute `req' responding in `res'.
|
||||||
|
require
|
||||||
|
req_attached: req /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
local
|
local
|
||||||
sess: WSF_ROUTER_SESSION
|
sess: WSF_ROUTER_SESSION
|
||||||
do
|
do
|
||||||
@@ -60,7 +63,7 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
36
library/server/wsf/security/filter/wsf_xss_filter.e
Normal file
36
library/server/wsf/security/filter/wsf_xss_filter.e
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
{WSF_XSS_FILTER}.
|
||||||
|
Simple anti cross-site scripting (XSS) filter.
|
||||||
|
Remove all suspicious strings from request parameters (query strings and form) before returning them to the application
|
||||||
|
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_XSS_FILTER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
|
||||||
|
WSF_FILTER
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||||
|
-- Execute the filter.
|
||||||
|
do
|
||||||
|
execute_next (create {WSF_XSS_REQUEST}.make_from_request (req), res)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
94
library/server/wsf/security/support/wsf_protection.e
Normal file
94
library/server/wsf/security/support/wsf_protection.e
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Security protection on values.
|
||||||
|
|
||||||
|
It could be to protect against XSS, SQL ... injections.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
EIS: "name=OWASP", "src=https://www.owasp.org/", "protocol=uri"
|
||||||
|
EIS: "name=OWASP XSS", "src=https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet", "protocol=uri"
|
||||||
|
EIS: "name=Regular expression protection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WSF_PROTECTION
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
is_valid: BOOLEAN
|
||||||
|
-- Is valid protection?
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- String Protection
|
||||||
|
|
||||||
|
string_8 (s: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||||
|
-- Safe string value from `s`.
|
||||||
|
-- If a thread is detected, either return Void, or filter out the threat.
|
||||||
|
require
|
||||||
|
is_valid: is_valid
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Value Protection
|
||||||
|
|
||||||
|
string_value (v: WSF_STRING): detachable WSF_STRING
|
||||||
|
-- Safe string value from `v`.
|
||||||
|
-- If a thread is detected, either return Void, or filter out the threat.
|
||||||
|
require
|
||||||
|
is_valid: is_valid
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
value (v: WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Safe value from `v`.
|
||||||
|
-- If a thread is detected, either return Void, or filter out the threat.
|
||||||
|
require
|
||||||
|
is_valid: is_valid
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} v as s then
|
||||||
|
Result := string_value (s)
|
||||||
|
elseif attached {WSF_MULTIPLE_STRING} v as ms then
|
||||||
|
Result := multiple_string_value (ms)
|
||||||
|
else
|
||||||
|
-- TODO
|
||||||
|
Result := v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
multiple_string_value (mv: WSF_MULTIPLE_STRING): detachable WSF_MULTIPLE_STRING
|
||||||
|
-- Safe multiple string value from `mv`.
|
||||||
|
-- If a thread is detected in any of the item, either return Void, or filter out the threat.
|
||||||
|
require
|
||||||
|
is_valid: is_valid
|
||||||
|
local
|
||||||
|
v: detachable WSF_STRING
|
||||||
|
do
|
||||||
|
-- TODO: check if the whole structure should be Void
|
||||||
|
-- when one item is filtered out, or if the structure could have
|
||||||
|
-- holes.
|
||||||
|
across
|
||||||
|
mv as ic
|
||||||
|
loop
|
||||||
|
v := string_value (ic.item)
|
||||||
|
if v = Void then
|
||||||
|
Result := Void
|
||||||
|
elseif Result = Void then
|
||||||
|
create Result.make_with_value (v)
|
||||||
|
else
|
||||||
|
Result.add_value (v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
490
library/server/wsf/security/support/wsf_protection_policy.e
Normal file
490
library/server/wsf/security/support/wsf_protection_policy.e
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
note
|
||||||
|
description: "Return data for WSF_REQUEST query and form parameters using different types of protection policy"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_PROTECTION_POLICY
|
||||||
|
|
||||||
|
-- TODO add header protection.
|
||||||
|
|
||||||
|
feature -- Query parameters
|
||||||
|
|
||||||
|
custom_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL; a_protections: ITERABLE [WSF_PROTECTION]): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with custom protections.
|
||||||
|
do
|
||||||
|
Result := custom_wsf_value (a_req.query_parameter (a_name), a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
predefined_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with all predefined protections.
|
||||||
|
-- check {WSF_PROTECTIONS} class.
|
||||||
|
do
|
||||||
|
Result := predefined_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with xss protection.
|
||||||
|
do
|
||||||
|
Result := xss_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_js_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with xss protection.
|
||||||
|
do
|
||||||
|
Result := xss_js_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with sql injection protection.
|
||||||
|
do
|
||||||
|
Result := sql_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
server_side_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with server side injection protection.
|
||||||
|
do
|
||||||
|
Result := server_side_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_abbreviated_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with XPath_abbreviated injection protection.
|
||||||
|
do
|
||||||
|
Result := xpath_abbreviated_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_expanded_query_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Query parameter name `a_name' with XPath expanded injection protection.
|
||||||
|
do
|
||||||
|
Result := xpath_expanded_value (a_req.query_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Form Parameters
|
||||||
|
|
||||||
|
custom_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL; a_protections: ITERABLE [WSF_PROTECTION]): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with custom protections.
|
||||||
|
do
|
||||||
|
Result := custom_wsf_value (a_req.form_parameter (a_name), a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
predefined_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with all predefined protections.
|
||||||
|
-- check {WSF_PROTECTIONS} class.
|
||||||
|
do
|
||||||
|
Result := predefined_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with xss protection.
|
||||||
|
do
|
||||||
|
Result := xss_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_js_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with xss protection.
|
||||||
|
do
|
||||||
|
Result := xss_js_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with sql injection protection.
|
||||||
|
do
|
||||||
|
Result := sql_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
server_side_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with server side injection protection.
|
||||||
|
do
|
||||||
|
Result := server_side_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_abbreviated_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with server Xpath abbreviated injection protection.
|
||||||
|
do
|
||||||
|
Result := xpath_abbreviated_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_expanded_form_parameter (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered Form parameter name `a_name' with server Xpath expanded injection protection.
|
||||||
|
do
|
||||||
|
Result := xpath_expanded_value (a_req.form_parameter (a_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Meta Variables
|
||||||
|
|
||||||
|
custom_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL; a_protections: ITERABLE [WSF_PROTECTION]): detachable WSF_VALUE
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with custom protections.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} custom_wsf_value (a_req.meta_variable (a_name), a_protections) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
predefined_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with predefined protections.
|
||||||
|
-- check {WSF_PROTECTIONS} class.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} predefined_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with xss protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} xss_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_js_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with xss protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} xss_js_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with sql injection protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} sql_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
server_side_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with server side injection protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} server_side_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_abbreviated_side_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with Xpath abbreviated injection protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} xpath_abbreviated_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_expanded_side_meta_variable (a_req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- Filtered CGI Meta variable name `a_name' with Xpath abbreviated injection protection.
|
||||||
|
require
|
||||||
|
a_name_valid: a_name /= Void and then not a_name.is_empty
|
||||||
|
do
|
||||||
|
if attached {WSF_STRING} xpath_expanded_value (a_req.meta_variable (a_name)) as l_result then
|
||||||
|
Result := l_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
feature -- HTTP_*
|
||||||
|
|
||||||
|
custom_http_accept (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_accept header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Accept: header from the current wgi_request, if there is one.
|
||||||
|
-- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_accept, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_accept_charset (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_accept_charset header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Accept-Charset: header from the current wgi_request, if there is one.
|
||||||
|
-- Example: 'iso-8859-1,*,utf-8'.
|
||||||
|
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_accept_charset, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_accept_encoding (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_accept_encoding header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Accept-Encoding: header from the current wgi_request, if there is one.
|
||||||
|
-- Example: 'gzip'.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_accept_encoding, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_accept_language (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_accept_language header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Accept-Language: header from the current wgi_request, if there is one.
|
||||||
|
-- Example: 'en'.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_accept_language, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_connection (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_connection header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Connection: header from the current wgi_request, if there is one.
|
||||||
|
-- Example: 'keep-alive'.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_connection, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_expect (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_expect header with custom protections `a_protections`.
|
||||||
|
-- The Expect request-header field is used to indicate that particular server behaviors are required by the client.
|
||||||
|
-- Example: '100-continue'.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_expect, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_host (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_host header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Host: header from the current wgi_request, if there is one.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_host, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_referer (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_referer header with custom protections `a_protections`.
|
||||||
|
-- The address of the page (if any) which referred the user agent to the current page.
|
||||||
|
-- This is set by the user agent.
|
||||||
|
-- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature.
|
||||||
|
-- In short, it cannot really be trusted.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_referer, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_user_agent (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_user_agent header with custom protections `a_protections`.
|
||||||
|
-- Contents of the User-Agent: header from the current wgi_request, if there is one.
|
||||||
|
-- This is a string denoting the user agent being which is accessing the page.
|
||||||
|
-- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586).
|
||||||
|
-- Among other things, you can use this value to tailor your page's
|
||||||
|
-- output to the capabilities of the user agent.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_user_agent, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_authorization (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_authorization header with custom protections `a_protections`.
|
||||||
|
-- Contents of the Authorization: header from the current wgi_request, if there is one.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_authorization, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_transfer_encoding (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_transfer_encoding header with custom protections `a_protections`.
|
||||||
|
-- Transfer-Encoding
|
||||||
|
-- for instance chunked.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_transfer_encoding, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_access_control_request_headers (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_access_control_request_headers header with custom protections `a_protections`.
|
||||||
|
-- Indicates which headers will be used in the actual request
|
||||||
|
-- as part of the preflight request
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_access_control_request_headers, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_if_match (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_if_match header with custom protections `a_protections`.
|
||||||
|
-- Existence check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_if_match, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_if_modified_since (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_if_modified_since header with custom protections `a_protections`.
|
||||||
|
-- Modification check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_if_modified_since, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_if_none_match (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_if_none_match header with custom protections `a_protections`.
|
||||||
|
-- Existence check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_if_none_match, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_if_range (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_if_range header with custom protections `a_protections`.
|
||||||
|
-- Existence check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_if_range, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_if_unmodified_since (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_if_unmodified_since header with custom protections `a_protections`.
|
||||||
|
-- Modification check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_if_unmodified_since, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_last_modified (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_last_modified header with custom protections `a_protections`.
|
||||||
|
-- Modification check on resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_last_modified, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_range (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_range header with custom protections `a_protections`.
|
||||||
|
-- Requested byte-range of resource.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_range, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_content_range (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_content_range header with custom protections `a_protections`.
|
||||||
|
-- Partial range of selected representation enclosed in message payload.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_content_range, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_http_content_encoding (a_req: WSF_REQUEST; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Filtered http_content_encoding header with custom protections `a_protections`.
|
||||||
|
-- Encoding (usually compression) of message payload.
|
||||||
|
do
|
||||||
|
Result := custom_string_value (a_req.http_content_encoding, a_protections)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
custom_wsf_value (a_value: detachable WSF_VALUE; a_protections: ITERABLE [WSF_PROTECTION]): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by all protections policy.
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, a_protections )
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_string_value (a_value: detachable READABLE_STRING_8; a_protections: ITERABLE [WSF_PROTECTION]): detachable READABLE_STRING_8
|
||||||
|
-- Return value `a_value` filtered by all protections policy.
|
||||||
|
do
|
||||||
|
Result := filter_string_value (a_value, a_protections )
|
||||||
|
end
|
||||||
|
|
||||||
|
predefined_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by all predefined protections policy.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value,
|
||||||
|
<<
|
||||||
|
l_wsf_xss.XSS,
|
||||||
|
l_wsf_xss.server_side,
|
||||||
|
l_wsf_xss.sql_injection,
|
||||||
|
l_wsf_xss.xpath_abbreviated,
|
||||||
|
l_wsf_xss.xpath_expanded
|
||||||
|
>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by xss protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.XSS>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
xss_js_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by xss-javascript protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.XSS_javascript>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
sql_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by sql injection protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.SQL_injection>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
server_side_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by server side injection protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.Server_side>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_abbreviated_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by xpath_abbreviated injection protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.Xpath_abbreviated>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
xpath_expanded_value (a_value: detachable WSF_VALUE): detachable WSF_VALUE
|
||||||
|
-- Return value `a_value` filtered by Xpath expanded injection protection.
|
||||||
|
local
|
||||||
|
l_wsf_xss: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := filter_wsf_value (a_value, <<l_wsf_xss.Xpath_expanded>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
filter_wsf_value (a_value: detachable WSF_VALUE; a_protections: ITERABLE [WSF_PROTECTION]): detachable WSF_VALUE
|
||||||
|
-- Filter value `a_value` with an array of protections policy `a_protections`.
|
||||||
|
require
|
||||||
|
a_protections_valid: across a_protections as ic all ic.item.is_valid end
|
||||||
|
local
|
||||||
|
prot: WSF_PROTECTION
|
||||||
|
do
|
||||||
|
if a_value /= Void then
|
||||||
|
Result := a_value
|
||||||
|
across
|
||||||
|
a_protections as ic
|
||||||
|
until
|
||||||
|
Result = Void
|
||||||
|
loop
|
||||||
|
prot := ic.item
|
||||||
|
check is_valid: prot.is_valid end
|
||||||
|
Result := prot.value (Result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
filter_string_value (a_value: detachable READABLE_STRING_8; a_protections: ITERABLE [WSF_PROTECTION] ): detachable READABLE_STRING_8
|
||||||
|
-- Filter value `a_value` with an array of protections policy `a_protections`.
|
||||||
|
require
|
||||||
|
all_protections_valid: across a_protections as ic all ic.item.is_valid end
|
||||||
|
local
|
||||||
|
v: WSF_STRING
|
||||||
|
prot: WSF_PROTECTION
|
||||||
|
do
|
||||||
|
if a_value /= Void then
|
||||||
|
Result := a_value
|
||||||
|
across
|
||||||
|
a_protections as ic
|
||||||
|
until
|
||||||
|
Result = Void
|
||||||
|
loop
|
||||||
|
prot := ic.item
|
||||||
|
check is_valid: prot.is_valid end
|
||||||
|
Result := prot.string_8 (Result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
114
library/server/wsf/security/support/wsf_protection_regexp.e
Normal file
114
library/server/wsf/security/support/wsf_protection_regexp.e
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
note
|
||||||
|
description: "Security protection based on Regular expression."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
EIS: "name=Regular expression protection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_PROTECTION_REGEXP
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_PROTECTION
|
||||||
|
|
||||||
|
create
|
||||||
|
make,
|
||||||
|
make_caseless,
|
||||||
|
make_with_regexp
|
||||||
|
|
||||||
|
convert
|
||||||
|
make_with_regexp ({REGULAR_EXPRESSION})
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_regexp_pattern: READABLE_STRING_8; a_caseless: BOOLEAN)
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
do
|
||||||
|
create r
|
||||||
|
r.set_caseless (a_caseless)
|
||||||
|
r.compile (a_regexp_pattern)
|
||||||
|
make_with_regexp (r)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_caseless (a_regexp_pattern: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
make (a_regexp_pattern, True)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_regexp (a_regexp: REGULAR_EXPRESSION)
|
||||||
|
do
|
||||||
|
regexp := a_regexp
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
regexp: REGULAR_EXPRESSION
|
||||||
|
|
||||||
|
feature -- String Protection
|
||||||
|
|
||||||
|
string_8 (s: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||||
|
local
|
||||||
|
reg: like regexp
|
||||||
|
do
|
||||||
|
reg := regexp
|
||||||
|
reg.match (s)
|
||||||
|
if reg.has_matched then
|
||||||
|
Result := Void
|
||||||
|
else
|
||||||
|
Result := s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
string_value (v: WSF_STRING): detachable WSF_STRING
|
||||||
|
local
|
||||||
|
vs: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
vs := v.url_encoded_value
|
||||||
|
if attached string_8 (vs) as s then
|
||||||
|
if vs = s then
|
||||||
|
Result := v
|
||||||
|
else
|
||||||
|
create Result.make (v.name, s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
is_valid: BOOLEAN
|
||||||
|
-- <Precursor>
|
||||||
|
-- i.e: if the association regular expression is successfully compiled.
|
||||||
|
do
|
||||||
|
Result := is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
is_compiled: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := regexp.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
compiled_regexp (p: STRING; caseless: BOOLEAN): REGULAR_EXPRESSION
|
||||||
|
require
|
||||||
|
p /= Void
|
||||||
|
do
|
||||||
|
create Result
|
||||||
|
Result.set_caseless (caseless)
|
||||||
|
Result.compile (p)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
100
library/server/wsf/security/support/wsf_protections.e
Normal file
100
library/server/wsf/security/support/wsf_protections.e
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
{WSF_PROTECTIONS}
|
||||||
|
Provide application security parterns to assist in Cross Site Scripting
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
EIS: "name=OWASP XSS", "src=https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet", "protocol=uri"
|
||||||
|
EIS: "name=Regular expression protection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
|
||||||
|
expanded class
|
||||||
|
WSF_PROTECTIONS
|
||||||
|
|
||||||
|
feature -- XSS patterns
|
||||||
|
|
||||||
|
XSS: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name= XSS", "src=https://community.apigee.com/questions/27198/xss-threat-protection-patterns.html#answer-27465", "protocol=uri"
|
||||||
|
once
|
||||||
|
create Result.make_caseless ("((\%%3C)|<)[^\n]+((\%%3E)|>)")
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
XSS_javascript: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name=JavaScript Injection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
once
|
||||||
|
Result := compiled_regexp ("<\s*script\b[^>]*>[^<]+<\s*/\s*script\s*>", True)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- XPath injections Patterns
|
||||||
|
|
||||||
|
XPath_abbreviated: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name=XPath Abbreviated Syntax Injection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
once
|
||||||
|
Result := compiled_regexp ("(/(@?[\w_?\w:\*]+(\[[^]]+\])*)?)+", True)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
XPath_expanded: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name=XPath Expanded Syntax Injection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
once
|
||||||
|
Result := compiled_regexp ("/?(ancestor(-or-self)?|descendant(-or-self)?|following(-sibling))", True)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Server side injection
|
||||||
|
|
||||||
|
Server_side: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name=Server-Side Include Injection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
once
|
||||||
|
|
||||||
|
Result := compiled_regexp ("<!--#(include|exec|echo|config|printenv)\s+.*", True)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- SQL injection Patterns
|
||||||
|
|
||||||
|
SQL_injection: WSF_PROTECTION_REGEXP
|
||||||
|
note
|
||||||
|
EIS: "name= SQL Injection", "src=https://docs.apigee.com/api-services/reference/regular-expression-protection", "protocol=uri"
|
||||||
|
once
|
||||||
|
Result := compiled_regexp ("[\s]*((delete)|(exec)|(drop\s*table)|(insert)|(shutdown)|(update)|(\bor\b))", True)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
compiled_regexp (p: STRING; caseless: BOOLEAN): REGULAR_EXPRESSION
|
||||||
|
require
|
||||||
|
p /= Void
|
||||||
|
do
|
||||||
|
create Result
|
||||||
|
Result.set_caseless (caseless)
|
||||||
|
Result.compile (p)
|
||||||
|
ensure
|
||||||
|
is_compiled: Result.is_compiled
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
260
library/server/wsf/security/wsf_xss_request.e
Normal file
260
library/server/wsf/security/wsf_xss_request.e
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
XSS request, redefine query_parameter and form_parameters filtering the data (using XSS protection)
|
||||||
|
before return the value.
|
||||||
|
The XSS protection pattern used is defined here :{WSF_PROTECTIONS}.XSS: WSF_PROTECTION
|
||||||
|
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_XSS_REQUEST
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_REQUEST
|
||||||
|
redefine
|
||||||
|
query_parameter,
|
||||||
|
form_parameter,
|
||||||
|
meta_variable,
|
||||||
|
http_accept,
|
||||||
|
http_accept_charset,
|
||||||
|
http_accept_encoding,
|
||||||
|
http_accept_language,
|
||||||
|
http_connection,
|
||||||
|
http_expect,
|
||||||
|
http_host,
|
||||||
|
http_referer,
|
||||||
|
http_user_agent,
|
||||||
|
http_authorization,
|
||||||
|
http_transfer_encoding,
|
||||||
|
http_access_control_request_headers,
|
||||||
|
http_if_match,
|
||||||
|
http_if_modified_since,
|
||||||
|
http_if_none_match,
|
||||||
|
http_if_range,
|
||||||
|
http_if_unmodified_since,
|
||||||
|
http_last_modified,
|
||||||
|
http_range,
|
||||||
|
http_content_range,
|
||||||
|
http_content_encoding
|
||||||
|
end
|
||||||
|
|
||||||
|
WSF_REQUEST_EXPORTER
|
||||||
|
|
||||||
|
WSF_PROTECTION_POLICY
|
||||||
|
|
||||||
|
create
|
||||||
|
make_from_request
|
||||||
|
|
||||||
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
|
make_from_request (req: WSF_REQUEST)
|
||||||
|
do
|
||||||
|
make_from_wgi (req.wgi_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Query parameters
|
||||||
|
|
||||||
|
query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := xss_query_parameter (Current, a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Form Parameters
|
||||||
|
|
||||||
|
form_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := xss_form_parameter (Current, a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Meta Variable
|
||||||
|
|
||||||
|
meta_variable (a_name: READABLE_STRING_GENERAL): detachable WSF_STRING
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := xss_meta_variable (Current, a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- HTTP_*
|
||||||
|
|
||||||
|
http_accept: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_accept (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_accept_charset: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_accept_charset (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_accept_encoding: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_accept_encoding (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_accept_language: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_accept_language (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_connection: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_connection (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_expect: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_expect (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_host: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_host (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_referer: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_referer (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_user_agent: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_user_agent (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_authorization: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_authorization (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_transfer_encoding: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_transfer_encoding (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_access_control_request_headers: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_access_control_request_headers (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_if_match: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_if_match (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_if_modified_since: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_if_modified_since (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_if_none_match: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_if_none_match (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_if_range: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_if_range (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_if_unmodified_since: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_if_unmodified_since (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_last_modified: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_last_modified (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_range: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_range (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_content_range: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_content_range (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
http_content_encoding: detachable READABLE_STRING_8
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
Result := custom_http_content_encoding (Current, <<l_protection.xss>>)
|
||||||
|
end
|
||||||
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -104,6 +104,15 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
feature -- Element change
|
feature -- Element change
|
||||||
|
|
||||||
|
set_content_type (a_content_type: detachable like content_type)
|
||||||
|
do
|
||||||
|
if a_content_type = Void then
|
||||||
|
get_content_type
|
||||||
|
else
|
||||||
|
content_type := a_content_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
set_max_age (sec: INTEGER)
|
set_max_age (sec: INTEGER)
|
||||||
do
|
do
|
||||||
header.put_cache_control ("max-age=" + sec.out)
|
header.put_cache_control ("max-age=" + sec.out)
|
||||||
@@ -227,6 +236,7 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
do
|
do
|
||||||
res.set_status_code (status_code)
|
res.set_status_code (status_code)
|
||||||
if status_code = {HTTP_STATUS_CODE}.not_found then
|
if status_code = {HTTP_STATUS_CODE}.not_found then
|
||||||
|
-- File not found, then no more data.
|
||||||
else
|
else
|
||||||
res.put_header_text (header.string)
|
res.put_header_text (header.string)
|
||||||
s := head
|
s := head
|
||||||
|
|||||||
129
library/server/wsf/tests/src/test_wsf_protection_policy.e
Normal file
129
library/server/wsf/tests/src/test_wsf_protection_policy.e
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {TEST_WSF_PROTECTION_POLICY}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_WSF_PROTECTION_POLICY
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
WSF_SERVICE
|
||||||
|
undefine
|
||||||
|
default_create
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Test
|
||||||
|
|
||||||
|
test_http_expect_attack_without_xss_protection
|
||||||
|
local
|
||||||
|
req: WSF_REQUEST
|
||||||
|
|
||||||
|
do
|
||||||
|
--| Case HTTP header expect attack, no filtered.
|
||||||
|
req := new_request (<<
|
||||||
|
["REQUEST_METHOD", "GET"],
|
||||||
|
["QUERY_STRING", ""],
|
||||||
|
["REQUEST_URI", "/cookie"],
|
||||||
|
["HTTP_EXPECT", "<script>alert(XSS attack)</script>"]
|
||||||
|
>>
|
||||||
|
)
|
||||||
|
-- no filter
|
||||||
|
assert ("HTTP_EXPECT <script>alert(XSS attack)</script>", attached req.http_expect as v and then v.is_case_insensitive_equal ("<script>alert(XSS attack)</script>"))
|
||||||
|
end
|
||||||
|
|
||||||
|
test_http_expect_attack_with_xss_protection
|
||||||
|
local
|
||||||
|
req: WSF_REQUEST
|
||||||
|
sec: WSF_PROTECTION_POLICY
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
create sec
|
||||||
|
--| Case HTTP header expect attack, filtered using {xss_regular_expression}
|
||||||
|
req := new_request (<<
|
||||||
|
["REQUEST_METHOD", "GET"],
|
||||||
|
["QUERY_STRING", ""],
|
||||||
|
["REQUEST_URI", "/xss_example"],
|
||||||
|
["HTTP_EXPECT", "<script>alert(XSS attack)</script>"]
|
||||||
|
>>
|
||||||
|
)
|
||||||
|
assert ("HTTP_EXPECT <script>alert(XSS attack)</script>", sec.custom_http_expect (req, <<l_protection.xss>>) = Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_http_expect_attack_with_xss_js_protection
|
||||||
|
local
|
||||||
|
req: WSF_REQUEST
|
||||||
|
sec: WSF_PROTECTION_POLICY
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
do
|
||||||
|
create sec
|
||||||
|
--| Case HTTP header expect attack, filtered using {xss_javascript_expression}
|
||||||
|
req := new_request (<<
|
||||||
|
["REQUEST_METHOD", "GET"],
|
||||||
|
["QUERY_STRING", ""],
|
||||||
|
["REQUEST_URI", "/xss_example"],
|
||||||
|
["HTTP_EXPECT", "<script>alert(XSS attack)</script>"]
|
||||||
|
>>
|
||||||
|
)
|
||||||
|
assert ("HTTP_EXPECT <script>alert(XSS attack)</script>", sec.custom_http_expect (req, <<l_protection.xss_javascript>>) = Void )
|
||||||
|
end
|
||||||
|
|
||||||
|
test_http_referer_attack_with_xss_js_protection_fails
|
||||||
|
local
|
||||||
|
req: WSF_REQUEST
|
||||||
|
sec: WSF_PROTECTION_POLICY
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
l_str: STRING
|
||||||
|
do
|
||||||
|
l_str:= "[
|
||||||
|
Referer: http://www.google.com/search?hl=en&q=fe525"-alert(1)-"d116a885fd5
|
||||||
|
]"
|
||||||
|
create sec
|
||||||
|
--| Case HTTP header referer attack, filtered using {xss_javascript_expression}
|
||||||
|
req := new_request (<<
|
||||||
|
["REQUEST_METHOD", "GET"],
|
||||||
|
["QUERY_STRING", ""],
|
||||||
|
["REQUEST_URI", "/xss_example"],
|
||||||
|
["HTTP_REFERER", l_str]
|
||||||
|
>>
|
||||||
|
)
|
||||||
|
assert ("HTTP_REFERER", attached sec.custom_http_referer (req, <<l_protection.xss_javascript>>) as v and then not v.is_empty )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_http_referer_attack_with_xss_protection
|
||||||
|
local
|
||||||
|
req: WSF_REQUEST
|
||||||
|
sec: WSF_PROTECTION_POLICY
|
||||||
|
l_protection: WSF_PROTECTIONS
|
||||||
|
l_str: STRING
|
||||||
|
do
|
||||||
|
l_str:= "[
|
||||||
|
Referer: http://www.google.com/search?hl=en&q=fe525"-alert(1)-"d116a885fd5
|
||||||
|
]"
|
||||||
|
create sec
|
||||||
|
--| Case HTTP header referer attack, filtered using {xss_javascript_expression}
|
||||||
|
req := new_request (<<
|
||||||
|
["REQUEST_METHOD", "GET"],
|
||||||
|
["QUERY_STRING", ""],
|
||||||
|
["REQUEST_URI", "/xss_example"],
|
||||||
|
["HTTP_REFERER", l_str]
|
||||||
|
>>
|
||||||
|
)
|
||||||
|
assert ("HTTP_REFERER", attached {READABLE_STRING_8} sec.custom_http_referer (req, <<l_protection.xss>>) as v and then not v.is_empty )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
new_request (a_meta: ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]): WSF_REQUEST_NULL
|
||||||
|
local
|
||||||
|
wgi_req: WGI_REQUEST
|
||||||
|
do
|
||||||
|
create {WGI_REQUEST_NULL} wgi_req.make_with_file (a_meta, io.input)
|
||||||
|
create Result.make_from_wgi (wgi_req)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
252
library/server/wsf/tests/src/test_xss_patterns.e
Normal file
252
library/server/wsf/tests/src/test_xss_patterns.e
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {TEST_XSS_PATTERNS}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
EIS: "name=XSS Filter Evasion Cheat Sheet", "src=https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet", "protocol=uri"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_XSS_PATTERNS
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
|
||||||
|
feature -- Tests
|
||||||
|
|
||||||
|
test_xss_locator
|
||||||
|
local
|
||||||
|
xss: WSF_XSS_REQUEST
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:= "[
|
||||||
|
';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
|
||||||
|
alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--
|
||||||
|
></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("XSS locator", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_xss_locator_short
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
'';!--"<XSS>=&{()}
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("XSS locator short", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_no_filter_evasion
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<SCRIPT SRC=http://xss.rocks/xss.js></SCRIPT>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("No filter evasion", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_filter_bypass_based_polyglot
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
'">><marquee><img src=x onerror=confirm(1)></marquee>"></plaintext\></|\><plaintext/onmouseover=prompt(1)>
|
||||||
|
<script>prompt(1)</script>@gmail.com<isindex formaction=javascript:alert(/XSS/) type=submit>'-->"></script>
|
||||||
|
<script>alert(document.cookie)</script>">
|
||||||
|
<img/id="confirm(1)"/alt="/"src="/"onerror=eval(id)>'">
|
||||||
|
<img src="http://www.shellypalmer.com/wp-content/images/2015/07/hacked-compressor.jpg">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Filter bypass based polyglot", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_image_xss_js_directive
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC="javascript:alert('XSS');">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Image XSS using the JavaScript directive", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_no_quotes_no_semicolon
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=javascript:alert('XSS')>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("No quotes and no semicolon", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_case_insensitive_xss_vector
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=JaVaScRiPt:alert('XSS')>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Case insensitive XSS attack vector", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_html_entities
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=javascript:alert("XSS")>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("HTML entities", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_grave_accent_obfuscation
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Grave accent obfuscation", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_malformed_a_tags
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
-- Skip the HREF attribute and get to the meat of the XXS... Submitted by David Cross ~ Verified on Chrome
|
||||||
|
s:="[
|
||||||
|
<a onmouseover="alert(document.cookie)">xxs link</a>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Malformed A tags", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_malformed_a_tags_2
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
-- Chrome loves to replace missing quotes for you... if you ever get stuck just leave them off and Chrome will put them
|
||||||
|
-- in the right place and fix your missing quotes on a URL or script.
|
||||||
|
s:="[
|
||||||
|
<a onmouseover=alert(document.cookie)>xxs link</a>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Malformed A tags", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_malformed_img
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Malformed IMG tags", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_from_char_code
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("fromCharCode", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_default_src_tag
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC=# onmouseover="alert('xxs')">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Default SRC tag to get past filters that check SRC domain", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_default_src_tag_2
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG SRC= onmouseover="alert('xxs')">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Default SRC tag by leaving it empty", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_default_src_tag_3
|
||||||
|
local
|
||||||
|
r: REGULAR_EXPRESSION
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s:="[
|
||||||
|
<IMG onmouseover="alert('xxs')">
|
||||||
|
]"
|
||||||
|
r:= xss_pattern.XSS.regexp
|
||||||
|
r.match (s)
|
||||||
|
assert ("Default SRC tag by leaving it out entirely", r.has_matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
xss_pattern: WSF_PROTECTIONS
|
||||||
|
|
||||||
|
end
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
<target name="server">
|
<target name="server">
|
||||||
<root class="TEST" feature="make"/>
|
<root class="TEST" feature="make"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/\.git$</exclude>
|
<exclude>/\.git$</exclude>
|
||||||
<exclude>/\.svn$</exclude>
|
<exclude>/\.svn$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option debug="false" warning="true">
|
<option debug="false" warning="true">
|
||||||
<assertions precondition="true" postcondition="true" check="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" loop="true" supplier_precondition="true"/>
|
||||||
@@ -21,12 +21,14 @@
|
|||||||
</library>
|
</library>
|
||||||
<library name="http" location="..\..\..\network\protocol\http\http.ecf" readonly="false"/>
|
<library name="http" location="..\..\..\network\protocol\http\http.ecf" readonly="false"/>
|
||||||
<library name="http_client" location="..\..\..\network\http_client\net_http_client.ecf" readonly="false"/>
|
<library name="http_client" location="..\..\..\network\http_client\net_http_client.ecf" readonly="false"/>
|
||||||
|
<library name="pcre" location="$ISE_LIBRARY\unstable\library\text\regexp\pcre\pcre.ecf"/>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
<library name="wsf" location="..\wsf.ecf" readonly="false">
|
<library name="wsf" location="..\wsf.ecf" readonly="false">
|
||||||
<option>
|
<option>
|
||||||
<assertions precondition="true" postcondition="true" check="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="wsf_security" location="..\wsf_security.ecf" readonly="false"/>
|
||||||
<library name="wsf_standalone" location="..\..\wsf\connector\standalone.ecf" readonly="false"/>
|
<library name="wsf_standalone" location="..\..\wsf\connector\standalone.ecf" readonly="false"/>
|
||||||
<cluster name="server" location=".\server\" recursive="true"/>
|
<cluster name="server" location=".\server\" recursive="true"/>
|
||||||
</target>
|
</target>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<target name="wsf">
|
<target name="wsf">
|
||||||
<root all_classes="true"/>
|
<root all_classes="true"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/\.git$</exclude>
|
<exclude>/\.git$</exclude>
|
||||||
<exclude>/\.svn$</exclude>
|
<exclude>/\.svn$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true">
|
<option warning="true">
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
3
library/server/wsf/wsf_compression-safe.ecf
Normal file
3
library/server/wsf/wsf_compression-safe.ecf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<redirection xmlns="http://www.eiffel.com/developers/xml/configuration-1-16-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-16-0 http://www.eiffel.com/developers/xml/configuration-1-16-0.xsd" uuid="C558E537-1259-4C94-8C49-117D7E821820" message="Obsolete: use wsf_compression.ecf !" location="wsf_compression.ecf">
|
||||||
|
</redirection>
|
||||||
20
library/server/wsf/wsf_compression.ecf
Normal file
20
library/server/wsf/wsf_compression.ecf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-16-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-16-0 http://www.eiffel.com/developers/xml/configuration-1-16-0.xsd" name="wsf_compression" uuid="C558E537-1259-4C94-8C49-117D7E821820" library_target="wsf_compression">
|
||||||
|
<target name="wsf_compression">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg.ecf"/>
|
||||||
|
<library name="http" location="..\..\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<library name="wsf" location="wsf.ecf" readonly="false"/>
|
||||||
|
<library name="zlib" location="$ISE_LIBRARY\unstable\library\compression\zlib\zlib.ecf" readonly="false"/>
|
||||||
|
<cluster name="compression" location=".\compression\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
<target name="wsf_extension">
|
<target name="wsf_extension">
|
||||||
<root all_classes="true"/>
|
<root all_classes="true"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/\.git$</exclude>
|
<exclude>/\.git$</exclude>
|
||||||
<exclude>/\.svn$</exclude>
|
<exclude>/\.svn$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true">
|
<option warning="true">
|
||||||
</option>
|
</option>
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
||||||
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
|
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
|
||||||
<library name="http" location="..\..\network\protocol\http\http.ecf"/>
|
<library name="http" location="..\..\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="process" location="$ISE_LIBRARY\library\process\base\base_process.ecf"/>
|
||||||
<library name="wsf" location="wsf.ecf"/>
|
<library name="wsf" location="wsf.ecf"/>
|
||||||
<library name="wsf_router_context" location="wsf_router_context.ecf" readonly="true"/>
|
<library name="wsf_router_context" location="wsf_router_context.ecf" readonly="true"/>
|
||||||
<cluster name="extension" location=".\extension\" recursive="true"/>
|
<cluster name="extension" location=".\extension\" recursive="true"/>
|
||||||
|
|||||||
22
library/server/wsf/wsf_security.ecf
Normal file
22
library/server/wsf/wsf_security.ecf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-16-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-16-0 http://www.eiffel.com/developers/xml/configuration-1-16-0.xsd" name="wsf_security" uuid="6684959A-6F63-4861-A98E-7E144AE77F2E" library_target="wsf_security">
|
||||||
|
<target name="wsf_security">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
||||||
|
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
|
||||||
|
<library name="http" location="..\..\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="pcre" location="$ISE_LIBRARY\unstable\library\text\regexp\pcre\pcre.ecf"/>
|
||||||
|
<library name="process" location="$ISE_LIBRARY\library\process\base\base_process.ecf"/>
|
||||||
|
<library name="wsf" location="wsf.ecf"/>
|
||||||
|
<library name="wsf_router_context" location="wsf_router_context.ecf" readonly="true"/>
|
||||||
|
<cluster name="security" location=".\security\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -69,8 +69,6 @@ feature -- Process
|
|||||||
|
|
||||||
process_group (g: ERROR_GROUP)
|
process_group (g: ERROR_GROUP)
|
||||||
-- <Precursor>
|
-- <Precursor>
|
||||||
local
|
|
||||||
l_errors: LIST [ERROR]
|
|
||||||
do
|
do
|
||||||
across
|
across
|
||||||
g.sub_errors as s
|
g.sub_errors as s
|
||||||
|
|||||||
12
tools/httpd/README.md
Normal file
12
tools/httpd/README.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Simple web server
|
||||||
|
=================
|
||||||
|
|
||||||
|
This server is very simple and limited, it is, for now:
|
||||||
|
- a file server
|
||||||
|
- a CGI handler (for `*.cgi` executables)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
httpd (--root path)
|
||||||
|
|
||||||
|
--root <path>: document directory for file server (default: www)
|
||||||
|
|
||||||
56
tools/httpd/httpd.ecf
Normal file
56
tools/httpd/httpd.ecf
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-17-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-17-0 http://www.eiffel.com/developers/xml/configuration-1-17-0.xsd" name="httpd" uuid="60DBA808-B014-47BB-BDEF-11B87C1DC6DE">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="http" location="..\..\library\network\protocol\http\http.ecf"/>
|
||||||
|
<library name="process" location="$ISE_LIBRARY\library\process\base\base_process.ecf"/>
|
||||||
|
<library name="wsf" location="..\..\library\server\wsf\wsf.ecf" readonly="false"/>
|
||||||
|
<library name="wsf_extension" location="..\..\library\server\wsf\wsf_extension.ecf" readonly="false"/>
|
||||||
|
</target>
|
||||||
|
<target name="httpd_standalone" extends="common">
|
||||||
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
|
<option warning="true">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone.ecf"/>
|
||||||
|
<cluster name="httpd" location=".\src" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="httpd_standalone_mt" extends="httpd_standalone">
|
||||||
|
<capability>
|
||||||
|
<concurrency support="thread" use="thread"/>
|
||||||
|
</capability>
|
||||||
|
</target>
|
||||||
|
<target name="httpd_standalone_st" extends="httpd_standalone">
|
||||||
|
<capability>
|
||||||
|
<concurrency support="none" use="none"/>
|
||||||
|
</capability>
|
||||||
|
</target>
|
||||||
|
<target name="httpd_cgi" extends="common">
|
||||||
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
|
<option warning="true">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<capability>
|
||||||
|
<concurrency use="scoop"/>
|
||||||
|
</capability>
|
||||||
|
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi.ecf"/>
|
||||||
|
<cluster name="httpd" location=".\src" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="httpd_libfcgi" extends="common">
|
||||||
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
|
<option warning="true">
|
||||||
|
<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.ecf"/>
|
||||||
|
<cluster name="httpd" location=".\src" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
9
tools/httpd/server.ini
Normal file
9
tools/httpd/server.ini
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
verbose=true
|
||||||
|
verbose_level=ALERT
|
||||||
|
port=9090
|
||||||
|
#max_concurrent_connections=100
|
||||||
|
#keep_alive_timeout=5
|
||||||
|
#max_keep_alive_requests=300
|
||||||
|
#max_tcp_clients=100
|
||||||
|
#socket_timeout=60
|
||||||
|
#socket_recv_timeout=15
|
||||||
31
tools/httpd/src/application.e
Normal file
31
tools/httpd/src/application.e
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
note
|
||||||
|
description : "simple application root class"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
-- Specific to `standalone' connector (the EiffelWeb server).
|
||||||
|
-- See `{WSF_STANDALONE_SERVICE_LAUNCHER}.initialize'
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("server.ini"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
95
tools/httpd/src/application_execution.e
Normal file
95
tools/httpd/src/application_execution.e
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
note
|
||||||
|
description : "simple application execution"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_ROUTED_EXECUTION
|
||||||
|
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Setup
|
||||||
|
|
||||||
|
cgi_file_extensions: ITERABLE [READABLE_STRING_GENERAL]
|
||||||
|
once
|
||||||
|
Result := <<"cgi">>
|
||||||
|
end
|
||||||
|
|
||||||
|
directory_index_file_names: ITERABLE [READABLE_STRING_GENERAL]
|
||||||
|
once
|
||||||
|
Result := <<"index.html">>
|
||||||
|
end
|
||||||
|
|
||||||
|
document_location: PATH
|
||||||
|
-- Root folder for the httpd files server.
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
d: detachable READABLE_STRING_GENERAL
|
||||||
|
once
|
||||||
|
Result := execution_environment.current_working_path.extended ("www")
|
||||||
|
if attached execution_environment.arguments as args then
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := args.argument_count
|
||||||
|
until
|
||||||
|
i > n or d /= Void
|
||||||
|
loop
|
||||||
|
if
|
||||||
|
attached args.argument (i) as v and then
|
||||||
|
v.same_string_general ("--root") and then
|
||||||
|
i < n
|
||||||
|
then
|
||||||
|
i := i + 1
|
||||||
|
d := args.argument (i)
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
if d /= Void then
|
||||||
|
create Result.make_from_string (d)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
setup_router
|
||||||
|
-- Setup `router'
|
||||||
|
local
|
||||||
|
cgi: WSF_CGI_HANDLER
|
||||||
|
cgi_cond: WSF_ROUTING_CONDITION
|
||||||
|
fs: WSF_FILE_SYSTEM_HANDLER
|
||||||
|
m: WSF_STARTS_WITH_MAPPING
|
||||||
|
cond: WSF_WITH_CONDITION_MAPPING
|
||||||
|
s: STRING_32
|
||||||
|
do
|
||||||
|
create cgi.make (document_location)
|
||||||
|
cgi_cond := create {WSF_ROUTING_FILE_EXISTS_CONDITION}.make (document_location) and create {WSF_ROUTING_EXTENSION_CONDITION}.make (cgi_file_extensions)
|
||||||
|
create cond.make (cgi_cond, cgi)
|
||||||
|
create s.make_empty
|
||||||
|
across
|
||||||
|
cgi_file_extensions as ic
|
||||||
|
loop
|
||||||
|
if not s.is_empty then
|
||||||
|
s.append_string_general (", ")
|
||||||
|
end
|
||||||
|
s.append_string_general ("*.")
|
||||||
|
s.append_string_general (ic.item)
|
||||||
|
end
|
||||||
|
cond.set_condition_description (s)
|
||||||
|
|
||||||
|
router.map (cond, Void)
|
||||||
|
|
||||||
|
create fs.make_with_path (document_location)
|
||||||
|
fs.enable_index
|
||||||
|
fs.set_directory_index (directory_index_file_names)
|
||||||
|
fs.set_not_found_handler (agent (i_uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE) do execute_default (req, res) end)
|
||||||
|
|
||||||
|
create m.make ("", fs)
|
||||||
|
router.map (m, router.methods_get)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
1
tools/httpd/www/home.html
Normal file
1
tools/httpd/www/home.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello EiffelWeb httpd server.
|
||||||
@@ -46,7 +46,7 @@ echo Uninstall framework: ewf
|
|||||||
|
|
||||||
echo Uninstall ewf examples
|
echo Uninstall ewf examples
|
||||||
%RDCMD% %TMP_CONTRIB_DIR%\examples\web\ewf
|
%RDCMD% %TMP_CONTRIB_DIR%\examples\web\ewf
|
||||||
%RDCMD% %TMP_CONTRIB_DIR%\examples\ewb\ewf_precomp
|
%RDCMD% %TMP_CONTRIB_DIR%\examples\web\ewf_precomp
|
||||||
|
|
||||||
echo Uninstall ewf wizard
|
echo Uninstall ewf wizard
|
||||||
%RDCMD% %TMP_TARGET_DIR%\help\wizards\ewf
|
%RDCMD% %TMP_TARGET_DIR%\help\wizards\ewf
|
||||||
|
|||||||
Reference in New Issue
Block a user