Extracted compression code from wsf, and provided new wsf_compression library.
Renamed features.
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
<?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">
|
||||
<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" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<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="thread"/>
|
||||
<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="zlib" location="$ISE_LIBRARY\unstable\library\compression\zlib\zlib-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>
|
||||
|
||||
@@ -7,7 +7,6 @@ class
|
||||
SERVICE_COMPRESSION_EXECUTION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_ROUTED_EXECUTION
|
||||
redefine
|
||||
initialize,
|
||||
@@ -29,12 +28,12 @@ feature {NONE} -- Initialization
|
||||
|
||||
setup_router
|
||||
local
|
||||
fhdl: WSF_FILE_SYSTEM_HANDLER
|
||||
fhdl: WSF_FILE_SYSTEM_HANDLER_WITH_COMPRESSION
|
||||
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_default_compression_format
|
||||
fhdl.enable_compression_for_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)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
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
|
||||
|
||||
create
|
||||
make_with_path,
|
||||
make_with_content_type_and_path,
|
||||
make_html_with_path,
|
||||
make,
|
||||
make_with_content_type,
|
||||
make_html
|
||||
|
||||
|
||||
note
|
||||
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)"
|
||||
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,325 @@
|
||||
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
|
||||
initialize_compression
|
||||
end
|
||||
|
||||
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_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
|
||||
|
||||
conneg : SERVER_CONTENT_NEGOTIATION
|
||||
|
||||
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
|
||||
h: HTTP_HEADER
|
||||
l_file: RAW_FILE
|
||||
l_content: detachable STRING
|
||||
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
|
||||
|
||||
-- Check the CLIENT request
|
||||
-- If the client support compression and one of the algorithms is `deflate_compression_format' we can do compression.
|
||||
-- and we need to add the corresponding 'Content-Encoding' with supported compression formats.
|
||||
if
|
||||
attached compression_encoding_variants (req, ct) 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
|
||||
create h.make
|
||||
create l_file.make_with_path (create {PATH}.make_from_string (f.path.name))
|
||||
check
|
||||
f_valid: l_file.exists and then l_file.is_access_readable
|
||||
end
|
||||
h.put_last_modified (file_date (l_file))
|
||||
l_file.open_read
|
||||
l_file.read_stream (l_file.count)
|
||||
l_file.close
|
||||
l_content := compressed_string (l_file.last_string, l_encoding)
|
||||
h.add_header ("Content-Encoding:" + l_encoding)
|
||||
h.add_header ("Vary:" + l_vary_header)
|
||||
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
|
||||
Precursor (f, req, res)
|
||||
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 -- Support Compress
|
||||
|
||||
compression_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
|
||||
l_compression_supported: LIST [STRING]
|
||||
l_compression: STRING
|
||||
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
|
||||
Result := conneg.encoding_preference (compression_supported_formats, l_http_encoding)
|
||||
if not Result.is_acceptable then
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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_formats.is_empty and then
|
||||
compression_enabled_media_types.has (ct) and then
|
||||
attached req.http_accept_encoding as l_http_encoding
|
||||
then
|
||||
l_compression_variants := conneg.encoding_preference (compression_supported_formats, 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_compression_format' 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 := compressed_string (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
|
||||
|
||||
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), 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 (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-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)"
|
||||
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,7 +39,7 @@ feature {NONE} -- Initialization
|
||||
|
||||
make_with_path (d: like document_root)
|
||||
do
|
||||
initialize_compression
|
||||
initialize
|
||||
max_age := -1
|
||||
if d.is_empty then
|
||||
document_root := execution_environment.current_working_path
|
||||
@@ -74,30 +74,11 @@ feature {NONE} -- Initialization
|
||||
is_hidden: BOOLEAN
|
||||
-- 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
|
||||
--
|
||||
initialize
|
||||
-- Initialize Current handler.
|
||||
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
|
||||
|
||||
mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION
|
||||
@@ -236,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)
|
||||
@@ -366,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
|
||||
@@ -379,74 +362,21 @@ feature -- Execution
|
||||
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)
|
||||
require
|
||||
f_valid: f.exists and then f.is_access_readable
|
||||
local
|
||||
ext: READABLE_STRING_32
|
||||
ct: detachable READABLE_STRING_8
|
||||
fres: WSF_FILE_RESPONSE
|
||||
dt: DATE_TIME
|
||||
h: HTTP_HEADER
|
||||
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
|
||||
-- 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)
|
||||
|
||||
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
|
||||
-- cache control
|
||||
@@ -464,9 +394,6 @@ feature -- Execution
|
||||
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
|
||||
res.send (fres)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
process_not_modified (a_utc_date: detachable DATE_TIME; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
@@ -724,186 +651,6 @@ feature {NONE} -- implementation: date time
|
||||
Result := d.date_time
|
||||
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
|
||||
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)"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<library name="http" location="..\..\network\protocol\http\http-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="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"/>
|
||||
<cluster name="router" location=".\router\" recursive="true">
|
||||
<file_rule>
|
||||
|
||||
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>
|
||||
Reference in New Issue
Block a user