Merge branch 'ewf_compression' of https://github.com/jvelilla/EWF into ewf_compression

This commit is contained in:
2016-12-06 12:53:41 +01:00
11 changed files with 166443 additions and 14 deletions

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-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="service_compression" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
<target name="service_compression">
<root class="SERVICE_COMPRESSION" feature="make_and_launch"/>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<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="zlib" location="$ISE_LIBRARY\unstable\library\compression\zlib\zlib-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,60 @@
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: WSF_FILE_SYSTEM_HANDLER
do
create fhdl.make_hidden ("www")
fhdl.set_directory_index (<<"index.html">>)
fhdl.set_default_compression
fhdl.set_custom_media_type ({HTTP_MIME_TYPES}.image_jpg)
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_with_request_methods ("/", 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,16 @@
<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>
<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>
</body>
</html>

View File

@@ -39,6 +39,7 @@ feature {NONE} -- Initialization
make_with_path (d: like document_root) make_with_path (d: like document_root)
do do
initialize_compression
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,30 @@ 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_compression
-- Initialize compression support, by default no compression
-- Gzip with the following media types
-- applications/javascript
-- application/json
-- application/xml
-- text/css
-- text/html
--
do
create conneg.make ("", "", "", "")
-- compression algorithms
create {ARRAYED_LIST [STRING]} compression_supported.make (0)
compression_supported.compare_objects
-- media types supported to compress.
create {ARRAYED_LIST [STRING]} media_types_supported.make (0)
media_types_supported.compare_objects
set_default_media_types
end
conneg : SERVER_CONTENT_NEGOTIATION
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
@@ -354,19 +379,74 @@ feature -- Execution
end end
end end
-- process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
-- local
-- ext: READABLE_STRING_32
-- ct: detachable READABLE_STRING_8
-- fres: WSF_FILE_RESPONSE
-- 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 (ct, f.path.name)
-- 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
-- fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
-- res.send (fres)
-- end
process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE) process_transfert (f: FILE; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
ext: READABLE_STRING_32 ext: READABLE_STRING_32
ct: detachable READABLE_STRING_8 ct: detachable READABLE_STRING_8
fres: WSF_FILE_RESPONSE fres: WSF_FILE_RESPONSE
dt: DATE_TIME dt: DATE_TIME
h: HTTP_HEADER
do do
ext := extension (f.path.name) ext := extension (f.path.name)
ct := extension_mime_mapping.mime_type (ext) ct := extension_mime_mapping.mime_type (ext)
if ct = Void then if ct = Void then
ct := {HTTP_MIME_TYPES}.application_force_download ct := {HTTP_MIME_TYPES}.application_force_download
end end
-- Compression
create h.make
if attached generated_compressed_output (req, f, h, ct) as l_content then
h.put_content_type (ct)
h.put_content_length (l_content.count)
-- cache control
create dt.make_now_utc
h.put_utc_date (dt)
if max_age >= 0 then
h.put_cache_control ("max-age=" +max_age.out)
if max_age > 0 then
dt := dt.twin
dt.second_add (max_age)
end
h.put_expires_date (dt)
end
res.set_status_code ({HTTP_STATUS_CODE}.ok)
res.put_header_text (h.string)
res.put_string (l_content)
else
create fres.make_with_content_type (ct, f.path.name) create fres.make_with_content_type (ct, f.path.name)
fres.set_status_code ({HTTP_STATUS_CODE}.ok) fres.set_status_code ({HTTP_STATUS_CODE}.ok)
-- cache control -- cache control
@@ -384,6 +464,9 @@ feature -- Execution
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head)) fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
res.send (fres) res.send (fres)
end end
end
process_not_modified (a_utc_date: detachable DATE_TIME; req: WSF_REQUEST; res: WSF_RESPONSE) process_not_modified (a_utc_date: detachable DATE_TIME; req: WSF_REQUEST; res: WSF_RESPONSE)
local local
@@ -641,6 +724,186 @@ feature {NONE} -- implementation: date time
Result := d.date_time Result := d.date_time
end end
feature -- Compression
Gzip: STRING = "gzip"
-- RFC 1952 (gzip compressed format)
Deflate: STRING = "deflate"
-- RFC 1951 (deflate compressed format)
Compress: STRING = "compress"
-- RFC 1950 (zlib compressed format)
compression_supported : LIST [STRING]
-- Server side compression supported formats.
-- Supported compression agorithms: `gzip', `deflate', `compress'.
-- identity, means no compression at all.
media_types_supported: LIST [STRING]
-- List of media types supported by compression.
set_default_compression
-- gzip default format
do
add_gzip
end
wipe_out_compression
-- Remove all items.
do
compression_supported.wipe_out
end
add_gzip
-- add 'gzip' format to the list of 'compression_supported' formats.
do
compression_supported.force (Gzip)
ensure
has_gzip: compression_supported.has (Gzip)
end
remove_gzip
-- remove 'gzip' format to the list of 'compression_supported' formats.
do
compression_supported.prune (Gzip)
ensure
not_gzip: not compression_supported.has (Gzip)
end
add_deflate
-- add 'deflate' format to the list of 'compression_supported' formats.
do
compression_supported.force (Deflate)
ensure
has_deflate: compression_supported.has (Deflate)
end
remove_deflate
-- remove 'deflate' format to the list of 'compression_supported' formats.
do
compression_supported.prune (Deflate)
ensure
not_deflate: not compression_supported.has (Deflate)
end
add_compress
-- add 'compress' format to the list of 'compression_supported' formats
do
compression_supported.force (Compress)
ensure
has_compress: compression_supported.has (Compress)
end
remove_compress
-- remove 'deflate' format to the list of 'compression_supported' formats.
do
compression_supported.prune (Compress)
ensure
no_compress: not compression_supported.has (Compress)
end
set_default_media_types
-- Default media types
-- applications/javascript
-- application/json
-- application/xml
-- text/css
-- text/html
do
media_types_supported.force ({HTTP_MIME_TYPES}.application_javascript)
media_types_supported.force ({HTTP_MIME_TYPES}.application_json)
media_types_supported.force ({HTTP_MIME_TYPES}.application_xml)
media_types_supported.force ({HTTP_MIME_TYPES}.text_css)
media_types_supported.force ({HTTP_MIME_TYPES}.text_html)
media_types_supported.force ({HTTP_MIME_TYPES}.image_png)
end
wipe_out_media_types
-- Remove all items.
do
media_types_supported.wipe_out
end
set_custom_media_type (a_media_type: STRING)
do
media_types_supported.force (a_media_type)
ensure
has_media_type: media_types_supported.has (a_media_type)
end
feature -- Support Compress
generated_compressed_output (req: WSF_REQUEST; f:FILE; h: HTTP_HEADER; ct: STRING): detachable STRING
-- If the client support compression and the server support one of the algorithms
-- compress it and update the response header.
local
l_file: RAW_FILE
l_compression_variants : HTTP_ACCEPT_ENCODING_VARIANTS
l_compression_supported : LIST [STRING]
l_compression : STRING
do
if
not compression_supported.is_empty and then
media_types_supported.has (ct) and then
attached req.http_accept_encoding as l_http_encoding
then
l_compression_variants := conneg.encoding_preference (compression_supported,l_http_encoding)
if
l_compression_variants.is_acceptable and then
attached l_compression_variants.encoding as l_encoding and then
attached l_compression_variants.vary_header_value as l_vary_header
then
create l_file.make_with_path (create {PATH}.make_from_string (f.path.name))
if l_file.exists then
l_file.open_read
h.put_last_modified (create {DATE_TIME}.make_from_epoch (l_file.date))
-- Check the CLIENT request
-- If the client support compression and one of the algorithms is `deflate' we can do compression.
-- and we need to add the corresponding 'Content-Ecoding' witht the supported algorithm.
l_file.read_stream (l_file.count)
Result := do_compress (l_file.last_string, l_encoding)
h.add_header ("Content-Encoding:" + l_encoding)
h.add_header ("Vary:" + l_vary_header)
l_file.close
end
end
end
end
feature -- Compress Data
do_compress (a_string: STRING; l_encoding: STRING): STRING
-- Compress `a_string' using `deflate'
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 (l_encoding), 8, {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 (l_encoding: STRING): INTEGER
do
if l_encoding.is_case_insensitive_equal_general (gzip) then
Result := {ZLIB_CONSTANTS}.z_default_window_bits + 16
elseif l_encoding.is_case_insensitive_equal_general (deflate) then
Result := -{ZLIB_CONSTANTS}.z_default_window_bits
else
check compress: l_encoding.is_case_insensitive_equal_general (compress) end
Result := {ZLIB_CONSTANTS}.z_default_window_bits
end
end
note note
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" copyright: "2011-2016, 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)"

View File

@@ -21,6 +21,7 @@
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/> <library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/> <library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/> <library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
<library name="zlib" location="$ISE_LIBRARY\unstable\library\compression\zlib\zlib-safe.ecf" readonly="false"/>
<library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/> <library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/>
<cluster name="router" location=".\router\" recursive="true"> <cluster name="router" location=".\router\" recursive="true">
<file_rule> <file_rule>