Compare commits
16 Commits
es17.05
...
compressio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7d0398ec6 | ||
|
|
267655d7bc | ||
|
|
e735da1bcb | ||
|
|
6425482070 | ||
|
|
818c3fb460 | ||
|
|
dac50b490d | ||
|
|
16d5076fe5 | ||
|
|
2748e1d9ee | ||
|
|
27ee20f99b | ||
|
|
9a3164df70 | ||
|
|
02383810b4 | ||
|
|
dbf5e76047 | ||
|
|
5c31905427 | ||
| e14bb568d2 | |||
| 05d37439bc | |||
|
|
99bf552b89 |
19
.travis.yml
19
.travis.yml
@@ -0,0 +1,19 @@
|
|||||||
|
language: eiffel
|
||||||
|
before_script:
|
||||||
|
- export current_dir=$PWD ; echo current_dir=$current_dir ; cd ..
|
||||||
|
- export ISE_VERSION=17.05; export ISE_BUILD=100416
|
||||||
|
- curl -sSL http://downloads.sourceforge.net/eiffelstudio/Eiffel_${ISE_VERSION}_gpl_${ISE_BUILD}-linux-x86-64.tar.bz2 | tar -x --bzip2
|
||||||
|
- export ISE_EIFFEL=$PWD/Eiffel_${ISE_VERSION} ; export ISE_PLATFORM=linux-x86-64
|
||||||
|
- export PATH=$PATH:$ISE_EIFFEL/studio/spec/$ISE_PLATFORM/bin:$PATH:$ISE_EIFFEL/tools/spec/$ISE_PLATFORM/bin
|
||||||
|
- echo `ec -version`
|
||||||
|
- cd $current_dir
|
||||||
|
- echo Check projects compilation status...
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- v1
|
||||||
|
|
||||||
|
script: compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false
|
||||||
|
group: stable
|
||||||
|
os: linux
|
||||||
|
|||||||
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>
|
||||||
@@ -16,8 +16,19 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
get (a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||||
|
do
|
||||||
|
Result := new_session (a_url).get ("", ctx)
|
||||||
|
end
|
||||||
|
|
||||||
|
custom (a_method: READABLE_STRING_8; a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||||
|
-- Response for `a_method' request based on `a_url' and optional `ctx'.
|
||||||
|
do
|
||||||
|
Result := new_session (a_url).custom (a_method, "", ctx)
|
||||||
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2015, 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
|
||||||
|
|||||||
@@ -55,12 +55,19 @@ feature -- Secure connection Helpers
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
-- Set `ssl_protocol' with `Ssl_23'.
|
-- Set `ssl_protocol' with `Ssl_23'.
|
||||||
do
|
-- Protocol not supported anymore.
|
||||||
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
|
obsolete
|
||||||
end
|
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||||
|
local
|
||||||
|
err: DEVELOPER_EXCEPTION
|
||||||
|
do
|
||||||
|
create err
|
||||||
|
err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2")
|
||||||
|
err.raise
|
||||||
|
end
|
||||||
|
|
||||||
set_secure_protocol_to_tls_1_0
|
set_secure_protocol_to_tls_1_0
|
||||||
-- Set `ssl_protocol' with `Tls_1_0'.
|
-- Set `ssl_protocol' with `Tls_1_0'.
|
||||||
do
|
do
|
||||||
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
|
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
|
||||||
@@ -176,7 +183,14 @@ feature -- Output
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat 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: "[
|
||||||
|
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
|
end
|
||||||
|
|||||||
36
library/security/jwt/src/errors/jwt_mismatched_alg_error.e
Normal file
36
library/security/jwt/src/errors/jwt_mismatched_alg_error.e
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {JWT_MISMATCHED_ALG_ERROR}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
JWT_MISMATCHED_ALG_ERROR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
JWT_ERROR
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_alg, a_header_alg: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
alg := a_alg
|
||||||
|
header_alg := a_header_alg
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
alg: READABLE_STRING_8
|
||||||
|
|
||||||
|
header_alg: READABLE_STRING_8
|
||||||
|
|
||||||
|
id: STRING = "ALG_MISMATCH"
|
||||||
|
|
||||||
|
message: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
Result := "Header alg [" + header_alg + "] does not match given alg [" + alg + "]!"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -118,6 +118,11 @@ feature {JWT_UTILITIES} -- Error reporting
|
|||||||
l_errors.extend (err)
|
l_errors.extend (err)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
report_mismatched_alg_error (alg, a_header_alg: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
report_error (create {JWT_MISMATCHED_ALG_ERROR}.make (alg, a_header_alg))
|
||||||
|
end
|
||||||
|
|
||||||
report_unsupported_alg_error (alg: READABLE_STRING_8)
|
report_unsupported_alg_error (alg: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))
|
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))
|
||||||
|
|||||||
@@ -266,11 +266,10 @@ feature {NONE} -- Implementation
|
|||||||
|
|
||||||
base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8
|
base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8
|
||||||
local
|
local
|
||||||
hs256: HMAC_SHA256
|
ut: JWT_UTILITIES
|
||||||
do
|
do
|
||||||
create hs256.make_ascii_key (a_secret)
|
create ut
|
||||||
hs256.update_from_string (s)
|
Result := ut.base64_hmacsha256 (s, a_secret)
|
||||||
Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {JWT_LOADER}."
|
description: "Loader and verifier to JWT token."
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
EIS: "name=Known Critical vulnerabilities in JWT libs", "protocol=URI", "src=https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/"
|
||||||
|
|
||||||
class
|
class
|
||||||
JWT_LOADER
|
JWT_LOADER
|
||||||
@@ -12,9 +12,13 @@ inherit
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
token (a_token_input: READABLE_STRING_8; a_secret: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
|
token (a_token_input: READABLE_STRING_8; a_alg: detachable READABLE_STRING_8; a_verification_key: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
|
||||||
-- Decoded token from `a_token_input` given the secret `a_secret`, and optional context `ctx`
|
-- Decoded token from `a_token_input` given the verification key `a_verification_key` and optional (but recommended) signature algorithm `a_alg`, and optional context `ctx`
|
||||||
-- used to specify eventual issuer and various parameters.
|
-- used to specify eventual issuer and various parameters.
|
||||||
|
-- WARNING: passing Void for `a_alg` is not safe, as the server should know which alg he used for tokens,
|
||||||
|
-- leaving the possibility to use the header alg is dangerous as client may use "none" and then bypass verification!
|
||||||
|
require
|
||||||
|
a_valid_alg: a_alg /= Void implies is_supporting_signature_algorithm (a_alg)
|
||||||
local
|
local
|
||||||
jws: JWS
|
jws: JWS
|
||||||
i,j,n: INTEGER
|
i,j,n: INTEGER
|
||||||
@@ -29,20 +33,27 @@ feature -- Access
|
|||||||
l_enc_payload := a_token_input.substring (i + 1, j - 1)
|
l_enc_payload := a_token_input.substring (i + 1, j - 1)
|
||||||
l_signature := a_token_input.substring (j + 1, n)
|
l_signature := a_token_input.substring (j + 1, n)
|
||||||
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
|
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
|
||||||
|
|
||||||
alg := signature_algorithm_from_encoded_header (l_enc_header)
|
alg := signature_algorithm_from_encoded_header (l_enc_header)
|
||||||
jws.set_algorithm (alg)
|
if a_alg /= Void then
|
||||||
if alg = Void then
|
if alg /= Void and then not alg.is_case_insensitive_equal_general (a_alg) then
|
||||||
-- Use default
|
jws.report_mismatched_alg_error (a_alg, alg)
|
||||||
alg := alg_hs256
|
else
|
||||||
|
alg := a_alg
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if alg = Void then
|
||||||
|
-- Use default
|
||||||
|
alg := alg_hs256
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
jws.set_algorithm (alg)
|
||||||
check alg_set: alg /= Void end
|
check alg_set: alg /= Void end
|
||||||
if ctx = Void or else not ctx.validation_ignored then
|
if ctx = Void or else not ctx.validation_ignored then
|
||||||
if not is_supporting_signature_algorithm (alg) then
|
if not is_supporting_signature_algorithm (alg) then
|
||||||
jws.report_unsupported_alg_error (alg)
|
jws.report_unsupported_alg_error (alg)
|
||||||
alg := alg_hs256
|
alg := alg_hs256
|
||||||
end
|
end
|
||||||
if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_secret, alg)) then
|
if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_verification_key, alg)) then
|
||||||
jws.report_unverified_token_error
|
jws.report_unverified_token_error
|
||||||
end
|
end
|
||||||
if
|
if
|
||||||
|
|||||||
@@ -61,7 +61,33 @@ feature -- Encoding
|
|||||||
do
|
do
|
||||||
create hs256.make_ascii_key (a_secret)
|
create hs256.make_ascii_key (a_secret)
|
||||||
hs256.update_from_string (s)
|
hs256.update_from_string (s)
|
||||||
Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
-- if Version >= EiffelStudio 17.11 then
|
||||||
|
-- Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
||||||
|
-- else
|
||||||
|
Result := base64_bytes_encoded_string (hs256.digest)
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
base64_bytes_encoded_string (a_bytes: SPECIAL [NATURAL_8]): STRING_8
|
||||||
|
-- Base64 string from `a_bytes`.
|
||||||
|
--| Note: to be removed when 17.11 is not latest release anymore.
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := a_bytes.count
|
||||||
|
create s.make (n)
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
s.append_code (a_bytes[i - 1])
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
Result := (create {BASE64}).encoded_string (s)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Decoding
|
feature -- Decoding
|
||||||
|
|||||||
@@ -54,7 +54,14 @@ feature -- Test
|
|||||||
|
|
||||||
create jwt_loader
|
create jwt_loader
|
||||||
|
|
||||||
if attached jwt_loader.token (tok, "secret", Void) as l_tok then
|
-- Use header alg!
|
||||||
|
if attached jwt_loader.token (tok, Void, "secret", Void) as l_tok then
|
||||||
|
assert ("no error", not l_tok.has_error)
|
||||||
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Use given alg!
|
||||||
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
@@ -96,21 +103,21 @@ feature -- Test
|
|||||||
create jwt_loader
|
create jwt_loader
|
||||||
|
|
||||||
-- Test with validation + exp
|
-- Test with validation + exp
|
||||||
if attached jwt_loader.token (tok, "secret", Void) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
|
|
||||||
create ctx
|
create ctx
|
||||||
ctx.set_time (now)
|
ctx.set_time (now)
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
dt := duplicated_time (now)
|
dt := duplicated_time (now)
|
||||||
dt.hour_add (5)
|
dt.hour_add (5)
|
||||||
ctx.set_time (dt)
|
ctx.set_time (dt)
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("exp error", l_tok.has_error)
|
assert ("exp error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -122,7 +129,7 @@ feature -- Test
|
|||||||
tok := jwt.encoded_string ("secret")
|
tok := jwt.encoded_string ("secret")
|
||||||
|
|
||||||
ctx.set_time (now)
|
ctx.set_time (now)
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("has nbf error", l_tok.has_error)
|
assert ("has nbf error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -130,7 +137,7 @@ feature -- Test
|
|||||||
dt.second_add (15)
|
dt.second_add (15)
|
||||||
ctx.set_time (dt)
|
ctx.set_time (dt)
|
||||||
|
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("has nbf error", l_tok.has_error)
|
assert ("has nbf error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -138,31 +145,51 @@ feature -- Test
|
|||||||
dt.minute_add (45)
|
dt.minute_add (45)
|
||||||
ctx.set_time (dt)
|
ctx.set_time (dt)
|
||||||
|
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test Issuer
|
-- Test Issuer
|
||||||
ctx.set_issuer ("urn:foobar")
|
ctx.set_issuer ("urn:foobar")
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("has iss error", l_tok.has_error)
|
assert ("has iss error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
ctx.set_issuer ("urn:foo")
|
ctx.set_issuer ("urn:foo")
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test Audience
|
-- Test Audience
|
||||||
ctx.set_audience ("urn:foobar")
|
ctx.set_audience ("urn:foobar")
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("has aud error", l_tok.has_error)
|
assert ("has aud error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
ctx.set_audience ("urn:foo")
|
ctx.set_audience ("urn:foo")
|
||||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||||
assert ("no error", not l_tok.has_error)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_mismatched_alg_jwt
|
||||||
|
local
|
||||||
|
jwt: JWS
|
||||||
|
payload: STRING
|
||||||
|
tok: STRING
|
||||||
|
do
|
||||||
|
payload := "[
|
||||||
|
{"iss":"joe","exp":1300819380,"http://example.com/is_root":true}
|
||||||
|
]"
|
||||||
|
|
||||||
|
create jwt.make_with_json_payload (payload)
|
||||||
|
jwt.set_algorithm ("none")
|
||||||
|
tok := jwt.encoded_string ("secret")
|
||||||
|
|
||||||
|
if attached (create {JWT_LOADER}).token (tok, "HS256", "secret", Void) as l_tok then
|
||||||
|
assert ("no error", not jwt.has_error)
|
||||||
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test_unsecured_jwt
|
test_unsecured_jwt
|
||||||
local
|
local
|
||||||
jwt: JWS
|
jwt: JWS
|
||||||
@@ -177,7 +204,11 @@ feature -- Test
|
|||||||
jwt.set_algorithm ("none")
|
jwt.set_algorithm ("none")
|
||||||
tok := jwt.encoded_string ("secret")
|
tok := jwt.encoded_string ("secret")
|
||||||
|
|
||||||
if attached (create {JWT_LOADER}).token (tok, "secret", Void) as l_tok then
|
if attached (create {JWT_LOADER}).token (tok, "none", "secret", Void) as l_tok then
|
||||||
|
assert ("no error", not jwt.has_error)
|
||||||
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
|
end
|
||||||
|
if attached (create {JWT_LOADER}).token (tok, Void, "secret", Void) as l_tok then
|
||||||
assert ("no error", not jwt.has_error)
|
assert ("no error", not jwt.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
||||||
-- Set `socket_timeout' with `a_nb_seconds'
|
-- Set `socket_timeout' with `a_nb_seconds'.
|
||||||
do
|
do
|
||||||
socket_timeout := a_nb_seconds
|
socket_timeout := a_nb_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -175,7 +175,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
||||||
-- Set `socket_recv_timeout' with `a_nb_seconds'
|
-- Set `socket_recv_timeout' with `a_nb_seconds'.
|
||||||
do
|
do
|
||||||
socket_recv_timeout := a_nb_seconds
|
socket_recv_timeout := a_nb_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -183,7 +183,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
||||||
-- Set `keep_alive_timeout' with `a_seconds'
|
-- Set `keep_alive_timeout' with `a_seconds'.
|
||||||
do
|
do
|
||||||
keep_alive_timeout := a_seconds
|
keep_alive_timeout := a_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -191,7 +191,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||||
-- Set `max_keep_alive_requests' with `nb'
|
-- Set `max_keep_alive_requests' with `nb'.
|
||||||
do
|
do
|
||||||
max_keep_alive_requests := nb
|
max_keep_alive_requests := nb
|
||||||
ensure
|
ensure
|
||||||
@@ -254,7 +254,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
mark_secure
|
mark_secure
|
||||||
-- Set is_secure in True
|
-- Set is_secure in True.
|
||||||
do
|
do
|
||||||
set_is_secure (True)
|
set_is_secure (True)
|
||||||
ensure
|
ensure
|
||||||
@@ -287,7 +287,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol (a_version: NATURAL)
|
set_secure_protocol (a_version: NATURAL)
|
||||||
-- Set `secure_protocol' with `a_version'
|
-- Set `secure_protocol' with `a_version'.
|
||||||
do
|
do
|
||||||
secure_protocol := a_version
|
secure_protocol := a_version
|
||||||
ensure
|
ensure
|
||||||
@@ -295,7 +295,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
||||||
-- Set `secure_protocol' with `a_ssl_version'
|
-- Set `secure_protocol' with `a_ssl_version'.
|
||||||
do
|
do
|
||||||
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
@@ -316,6 +316,8 @@ feature -- SSL Helpers
|
|||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
-- Set `secure_protocol' with `Ssl_23'.
|
-- Set `secure_protocol' with `Ssl_23'.
|
||||||
|
obsolete
|
||||||
|
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,16 @@ feature -- Access
|
|||||||
feature -- SSL Helpers
|
feature -- SSL Helpers
|
||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
-- Set `secure_protocol' with `Ssl_23'.
|
-- Set `ssl_protocol' with `Ssl_23'.
|
||||||
|
-- Protocol not supported anymore.
|
||||||
|
obsolete
|
||||||
|
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||||
|
local
|
||||||
|
err: DEVELOPER_EXCEPTION
|
||||||
do
|
do
|
||||||
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
|
create err
|
||||||
|
err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2")
|
||||||
|
err.raise
|
||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol_to_tls_1_0
|
set_secure_protocol_to_tls_1_0
|
||||||
@@ -67,7 +74,7 @@ feature -- SSL Helpers
|
|||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2014, 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
|
||||||
|
|||||||
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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
21
library/server/wsf/wsf_compression-safe.ecf
Normal file
21
library/server/wsf/wsf_compression-safe.ecf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?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="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" void_safety="all">
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||||
|
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="wsf" location="wsf-safe.ecf" readonly="false"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<library name="zlib" location="$ISE_LIBRARY\unstable\library\compression\zlib\zlib-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="compression" location=".\compression\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
18
library/server/wsf/wsf_compression.ecf
Normal file
18
library/server/wsf/wsf_compression.ecf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?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="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" void_safety="none">
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg.ecf"/>
|
||||||
|
<library name="wsf" location="wsf.ecf"/>
|
||||||
|
<cluster name="compression" location=".\compression\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
</option>
|
</option>
|
||||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false" use_application_options="true"/>
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false" use_application_options="true"/>
|
||||||
<cluster name="src" location="src\" recursive="true"/>
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
<override name="override" location="override\" recursive="true"/>
|
|
||||||
</target>
|
</target>
|
||||||
<target name="hello_cgi" extends="hello_dev">
|
<target name="hello_cgi" extends="hello_dev">
|
||||||
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
|
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user