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

@@ -39,6 +39,7 @@ feature {NONE} -- Initialization
make_with_path (d: like document_root)
do
initialize_compression
max_age := -1
if d.is_empty then
document_root := execution_environment.current_working_path
@@ -73,6 +74,30 @@ 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
--
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
@@ -354,37 +379,95 @@ 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)
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
create fres.make_with_content_type (ct, f.path.name)
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
-- 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
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)
-- 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
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)
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
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
end
process_not_modified (a_utc_date: detachable DATE_TIME; req: WSF_REQUEST; res: WSF_RESPONSE)
local
h: HTTP_HEADER
@@ -641,6 +724,186 @@ 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)"

View File

@@ -21,6 +21,7 @@
<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>