Files
EWF/library/server/wsf/src/response/wsf_file_response.e
Jocelyn Fiat cc4ef1a575 Better support for unicode path and values.
Added WSF_REQUEST.percent_encoded_path_info: READABLE_STRING_8
    to keep url encoded path info, as it is useful for specific component

The router is now using WSF_REQUEST.percent_encoded_path_info
    since URI_TEMPLATE are handling URI (and not IRI)
    this fixes an issue with unicode path parameters.

This should not break existing code, and this fixes various unicode related issues related
   to PATH parameter and path info
   but also any component using file names.

(required EiffelStudio >= 7.2)
2013-06-12 18:03:11 +02:00

318 lines
6.4 KiB
Plaintext

note
description : "Objects that ..."
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
WSF_FILE_RESPONSE
inherit
WSF_RESPONSE_MESSAGE
create
make_with_path,
make_with_content_type_and_path,
make_html_with_path,
make,
make_with_content_type,
make_html
feature {NONE} -- Initialization
make_with_path (a_path: PATH)
do
set_status_code ({HTTP_STATUS_CODE}.ok)
file_path := a_path
get_content_type
initialize
end
make_with_content_type_and_path (a_content_type: READABLE_STRING_8; a_path: PATH)
do
set_status_code ({HTTP_STATUS_CODE}.ok)
file_path := a_path
content_type := a_content_type
initialize
end
make_html_with_path (a_path: PATH)
-- Initialize `Current'.
do
make_with_content_type_and_path ({HTTP_MIME_TYPES}.text_html, a_path)
end
make (a_file_name: READABLE_STRING_GENERAL)
do
make_with_path (create {PATH}.make_from_string (a_file_name))
end
make_with_content_type (a_content_type: READABLE_STRING_8; a_file_name: READABLE_STRING_GENERAL)
-- Initialize `Current'.
do
make_with_content_type_and_path (a_content_type, create {PATH}.make_from_string (a_file_name))
end
make_html (a_filename: READABLE_STRING_GENERAL)
-- Initialize `Current'.
do
make_with_content_type ({HTTP_MIME_TYPES}.text_html, a_filename)
end
initialize
local
h: like header
do
get_file_exists
create h.make
header := h
h.put_content_type (content_type)
if file_exists then
if attached file_last_modified as dt then
h.put_last_modified (dt)
end
get_file_size
if file_size = 0 then
set_status_code ({HTTP_STATUS_CODE}.not_found)
else
set_status_code ({HTTP_STATUS_CODE}.ok)
end
else
set_status_code ({HTTP_STATUS_CODE}.not_found)
end
update_content_length
end
update_content_length
local
n: INTEGER
do
if file_exists then
n := file_size
if attached head as h then
n := n + h.count
end
if attached bottom as b then
n := n + b.count
end
else
n := 0
end
content_length := n
header.put_content_length (n)
end
feature -- Element change
set_expires_in_seconds (sec: INTEGER)
do
set_expires (sec.out)
end
set_expires (s: STRING)
do
header.put_expires_string (s)
end
set_no_cache
local
h: like header
do
h := header
h.put_expires (0)
h.put_cache_control ("no-cache, must-revalidate")
h.put_pragma_no_cache
end
feature -- Access
status_code: INTEGER assign set_status_code
header: HTTP_HEADER
content_length: INTEGER
-- Content-Length of the response
content_type: READABLE_STRING_8
-- Content-Type of the response
file_path: path
-- File path
file_name: READABLE_STRING_8
obsolete
"Use `file_path.name' for unicode support [2013-may]"
do
Result := file_path.utf_8_name
end
file_exists: BOOLEAN
-- File exists?
file_size: INTEGER
-- Size of file `file_path'
head, bottom: detachable READABLE_STRING_8
-- Eventual head and bottom part
-- before and after the file content.
feature -- Settings
answer_head_request_method: BOOLEAN assign set_answer_head_request_method
-- For HEAD request method, only http header should be sent
feature -- Element change
set_status_code (c: like status_code)
-- Set `status_code' to `c'.
require
valid_status_code: c > 0
do
status_code := c
ensure
status_code_set: status_code = c
end
set_answer_head_request_method (b: BOOLEAN)
-- Set answer_head_request_method' to `b'.
do
answer_head_request_method := b
end
set_head (s: like head)
-- Set `head' to `s'
-- it also change the `content_length' and associated value in `header'
do
head := s
update_content_length
end
set_bottom (s: like bottom)
-- Set `bottom' to `s'
-- it also change the `content_length' and associated value in `header'
do
bottom := s
update_content_length
end
feature {WSF_RESPONSE} -- Output
send_to (res: WSF_RESPONSE)
local
s: detachable READABLE_STRING_8
do
res.set_status_code (status_code)
if status_code = {HTTP_STATUS_CODE}.not_found then
else
res.put_header_text (header.string)
s := head
if s /= Void then
res.put_string (s)
end
if not answer_head_request_method then
send_file_content_to (file_path, res)
end
s := bottom
if s /= Void then
res.put_string (s)
end
end
end
feature {NONE} -- Implementation: file system helper
get_file_exists
-- Get `file_exists'
local
f: RAW_FILE
do
create f.make_with_path (file_path)
file_exists := f.exists
end
get_file_size
-- Get `file_size' from file named `file_path'
require
file_exists: file_exists
local
f: RAW_FILE
do
create f.make_with_path (file_path)
file_size := f.count
end
file_last_modified: detachable DATE_TIME
-- Get `file_size' from file named `file_path'
require
file_exists: file_exists
local
f: RAW_FILE
do
create f.make_with_path (file_path)
create Result.make_from_epoch (f.change_date)
end
file_extension (fn: PATH): STRING_32
-- Extension of file `fn'.
do
if attached fn.extension as ext then
Result := ext
else
create Result.make_empty
end
end
feature -- Content-type related
get_content_type
-- Content type associated with `file_path'
local
m_map: HTTP_FILE_EXTENSION_MIME_MAPPING
m: detachable READABLE_STRING_8
do
create m_map.make_default
m := m_map.mime_type (file_extension (file_path).as_lower)
if m = Void then
m := {HTTP_MIME_TYPES}.application_force_download
end
content_type := m
end
feature {NONE} -- Implementation: output
send_file_content_to (fn: PATH; res: WSF_RESPONSE)
-- Send the content of file `fn'
require
string_not_empty: not fn.is_empty
is_readable: (create {RAW_FILE}.make_with_path (fn)).is_readable
file_exists: file_exists
local
f: RAW_FILE
do
create f.make_with_path (fn)
check f.is_readable end
f.open_read
from
until
f.exhausted
loop
f.read_stream (4_096)
res.put_string (f.last_string)
end
f.close
end
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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