Compare commits

...

16 Commits

Author SHA1 Message Date
Jocelyn Fiat
a7d0398ec6 Introduce WSF_COMPRESSION and applied to WSF_*_WITH_COMPRESSION classes.
Modified the example to send the file with or without compression.
2017-09-01 18:59:18 +02:00
jvelilla
267655d7bc Update code, comment style and removed hardcoded value. 2017-08-18 13:55:54 -03:00
jvelilla
e735da1bcb Merge branch 'ewf_compression' of https://github.com/jocelyn/EWF into ewf_compression_2017 2017-08-18 09:52:03 -03:00
Jocelyn Fiat
6425482070 Fixed ecf by removing the override declaration. 2017-08-08 15:55:52 +02:00
Jocelyn Fiat
818c3fb460 Made compilable with EiffelStudio 17.05 and probably before as well. 2017-08-08 15:54:21 +02:00
Jocelyn Fiat
dac50b490d Added output for the travis CI job. 2017-08-08 14:10:12 +02:00
Jocelyn Fiat
16d5076fe5 Added Travis CI support with 17.05. 2017-08-08 14:03:39 +02:00
Jocelyn Fiat
2748e1d9ee Now JWT_LOADER takes the alg as argument, to avoid security issue where the lib is taking alg from the header (which may be a bad security weakness). 2017-07-11 23:32:11 +02:00
Jocelyn Fiat
27ee20f99b Added convenient get and custom functions on HTTP_CLIENT directly. 2017-07-11 23:29:42 +02:00
Javier Velilla
9a3164df70 Merge pull request #178 from jvelilla/ewf_ssl
Updated EWF  http_network, websocket, httpd to use the latest EiffelN…
2017-06-23 09:53:26 -03:00
jvelilla
02383810b4 Fixed bad identation
Updated date to current date in obsolte message.
2017-06-23 09:51:59 -03:00
jvelilla
dbf5e76047 Updated EWF network and httpd libraries.
Updated features using ssl_2 and ssl_3 as obsolete and raise a
developer exception.
2017-06-22 10:23:56 -03:00
jvelilla
5c31905427 Updated EWF http_network, websocket, httpd to use the latest EiffelNet SSL
version.
2017-06-21 18:34:07 -03:00
e14bb568d2 Extracted compression code from wsf, and provided new wsf_compression library.
Renamed features.
2016-12-06 14:18:51 +01:00
05d37439bc Merge branch 'ewf_compression' of https://github.com/jvelilla/EWF into ewf_compression 2016-12-06 12:53:41 +01:00
jvelilla
99bf552b89 Added compression support to WSF_FILE_SYSTEM_HANDLER.
Added a simple example using eiffel web compression.
2016-11-29 18:17:44 -03:00
28 changed files with 166851 additions and 46 deletions

View File

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

View File

@@ -0,0 +1,4 @@
port=9090
verbose=true
socket_recv_timeout=15
keep_alive_timeout=30

View 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

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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

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

View File

@@ -16,8 +16,19 @@ feature -- Access
deferred
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
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)"
source: "[
Eiffel Software

View File

@@ -55,12 +55,19 @@ feature -- Secure connection Helpers
end
set_secure_protocol_to_ssl_2_or_3
-- Set `ssl_protocol' with `Ssl_23'.
do
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
end
-- 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
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'.
do
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
@@ -176,7 +183,14 @@ feature -- Output
end
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)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,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

View File

@@ -118,6 +118,11 @@ feature {JWT_UTILITIES} -- Error reporting
l_errors.extend (err)
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)
do
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))

View File

@@ -266,11 +266,10 @@ feature {NONE} -- Implementation
base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8
local
hs256: HMAC_SHA256
ut: JWT_UTILITIES
do
create hs256.make_ascii_key (a_secret)
hs256.update_from_string (s)
Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
create ut
Result := ut.base64_hmacsha256 (s, a_secret)
end
end

View File

@@ -1,8 +1,8 @@
note
description: "Summary description for {JWT_LOADER}."
author: ""
description: "Loader and verifier to JWT token."
date: "$Date$"
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
JWT_LOADER
@@ -12,9 +12,13 @@ inherit
feature -- Access
token (a_token_input: READABLE_STRING_8; a_secret: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
-- Decoded token from `a_token_input` given the secret `a_secret`, and optional context `ctx`
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 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.
-- 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
jws: JWS
i,j,n: INTEGER
@@ -29,20 +33,27 @@ feature -- Access
l_enc_payload := a_token_input.substring (i + 1, j - 1)
l_signature := a_token_input.substring (j + 1, n)
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
alg := signature_algorithm_from_encoded_header (l_enc_header)
jws.set_algorithm (alg)
if alg = Void then
-- Use default
alg := alg_hs256
if a_alg /= Void then
if alg /= Void and then not alg.is_case_insensitive_equal_general (a_alg) then
jws.report_mismatched_alg_error (a_alg, alg)
else
alg := a_alg
end
else
if alg = Void then
-- Use default
alg := alg_hs256
end
end
jws.set_algorithm (alg)
check alg_set: alg /= Void end
if ctx = Void or else not ctx.validation_ignored then
if not is_supporting_signature_algorithm (alg) then
jws.report_unsupported_alg_error (alg)
alg := alg_hs256
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
end
if

View File

@@ -61,7 +61,33 @@ feature -- Encoding
do
create hs256.make_ascii_key (a_secret)
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
feature -- Decoding

View File

@@ -54,7 +54,14 @@ feature -- Test
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 ("same payload", l_tok.claimset.string.same_string (payload))
end
@@ -96,21 +103,21 @@ feature -- Test
create jwt_loader
-- 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 ("same payload", l_tok.claimset.string.same_string (payload))
end
create ctx
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)
end
dt := duplicated_time (now)
dt.hour_add (5)
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)
end
@@ -122,7 +129,7 @@ feature -- Test
tok := jwt.encoded_string ("secret")
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)
end
@@ -130,7 +137,7 @@ feature -- Test
dt.second_add (15)
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)
end
@@ -138,31 +145,51 @@ feature -- Test
dt.minute_add (45)
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)
end
-- Test Issuer
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)
end
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)
end
-- Test Audience
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)
end
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)
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
local
jwt: JWS
@@ -177,7 +204,11 @@ feature -- Test
jwt.set_algorithm ("none")
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 ("same payload", l_tok.claimset.string.same_string (payload))
end

View File

@@ -167,7 +167,7 @@ feature -- Element change
end
set_socket_timeout (a_nb_seconds: like socket_timeout)
-- Set `socket_timeout' with `a_nb_seconds'
-- Set `socket_timeout' with `a_nb_seconds'.
do
socket_timeout := a_nb_seconds
ensure
@@ -175,7 +175,7 @@ feature -- Element change
end
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
socket_recv_timeout := a_nb_seconds
ensure
@@ -183,7 +183,7 @@ feature -- Element change
end
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
keep_alive_timeout := a_seconds
ensure
@@ -191,7 +191,7 @@ feature -- Element change
end
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
max_keep_alive_requests := nb
ensure
@@ -254,7 +254,7 @@ feature -- Element change
end
mark_secure
-- Set is_secure in True
-- Set is_secure in True.
do
set_is_secure (True)
ensure
@@ -287,7 +287,7 @@ feature -- Element change
end
set_secure_protocol (a_version: NATURAL)
-- Set `secure_protocol' with `a_version'
-- Set `secure_protocol' with `a_version'.
do
secure_protocol := a_version
ensure
@@ -295,7 +295,7 @@ feature -- Element change
end
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
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
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' with `Ssl_23'.
obsolete
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
deferred
end

View File

@@ -36,9 +36,16 @@ feature -- Access
feature -- SSL Helpers
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
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
set_secure_protocol_to_tls_1_0
@@ -67,7 +74,7 @@ feature -- SSL Helpers
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)"
source: "[
Eiffel Software

View 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

View File

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

View File

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

View File

@@ -39,6 +39,7 @@ feature {NONE} -- Initialization
make_with_path (d: like document_root)
do
initialize
max_age := -1
if d.is_empty then
document_root := execution_environment.current_working_path
@@ -73,6 +74,11 @@ feature {NONE} -- Initialization
is_hidden: BOOLEAN
-- Current mapped handler should be hidden from self documentation
initialize
-- Initialize Current handler.
do
end
feature -- 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)
create f.make_with_path (fn)
if f.exists then
if f.is_readable then
if f.is_access_readable then
if f.is_directory then
if index_disabled then
process_directory_index_disabled (uri, req, res)
@@ -341,6 +347,8 @@ feature -- Execution
end
process_file (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
require
f_valid: f.exists and then f.is_access_readable
do
if
attached req.meta_string_variable ("HTTP_IF_MODIFIED_SINCE") as s_if_modified_since and then
@@ -355,6 +363,8 @@ feature -- Execution
end
process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
require
f_valid: f.exists and then f.is_access_readable
local
ext: READABLE_STRING_32
ct: detachable READABLE_STRING_8

View File

@@ -104,6 +104,15 @@ feature {NONE} -- Initialization
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)
do
header.put_cache_control ("max-age=" + sec.out)
@@ -227,6 +236,7 @@ feature {WSF_RESPONSE} -- Output
do
res.set_status_code (status_code)
if status_code = {HTTP_STATUS_CODE}.not_found then
-- File not found, then no more data.
else
res.put_header_text (header.string)
s := head

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

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

View File

@@ -24,7 +24,6 @@
</option>
<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"/>
<override name="override" location="override\" recursive="true"/>
</target>
<target name="hello_cgi" extends="hello_dev">
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>