Compare commits
28 Commits
es_rev1009
...
es_rev1010
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -13,6 +13,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,7 @@ 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.
|
||||||
|
|
||||||
### 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)
|
||||||
|
|||||||
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
|
||||||
|
|||||||
@@ -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,34 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that ..."
|
||||||
|
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-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,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
|
||||||
|
|||||||
@@ -8,21 +8,12 @@ deferred class
|
|||||||
WSF_URI_FILTER_HANDLER
|
WSF_URI_FILTER_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
WSF_FILTER_HANDLER [WSF_URI_HANDLER]
|
WSF_EXECUTE_FILTER_HANDLER
|
||||||
|
|
||||||
WSF_URI_HANDLER
|
WSF_URI_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
|
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,15 @@ class
|
|||||||
WSF_URI_RESPONSE_AGENT_HANDLER
|
WSF_URI_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
|
WSF_EXECUTE_RESPONSE_AGENT_HANDLER
|
||||||
|
|
||||||
WSF_URI_RESPONSE_HANDLER
|
WSF_URI_RESPONSE_HANDLER
|
||||||
|
|
||||||
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
|
||||||
@@ -20,16 +22,8 @@ feature -- Response
|
|||||||
Result_attached: Result /= Void
|
Result_attached: Result /= Void
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
|
||||||
-- Execute request handler
|
|
||||||
do
|
|
||||||
res.send (response (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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -8,21 +8,12 @@ deferred class
|
|||||||
WSF_URI_TEMPLATE_FILTER_HANDLER
|
WSF_URI_TEMPLATE_FILTER_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
WSF_FILTER_HANDLER [WSF_URI_TEMPLATE_HANDLER]
|
WSF_EXECUTE_FILTER_HANDLER
|
||||||
|
|
||||||
WSF_URI_TEMPLATE_HANDLER
|
WSF_URI_TEMPLATE_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
|
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,15 @@ 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
|
||||||
|
|
||||||
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
|
||||||
@@ -20,16 +22,8 @@ feature -- Response
|
|||||||
Result_attached: Result /= Void
|
Result_attached: Result /= Void
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Execution
|
|
||||||
|
|
||||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
|
||||||
-- Execute request handler
|
|
||||||
do
|
|
||||||
res.send (response (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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
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"/>
|
||||||
|
|||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user