Files
EWF/library/server/wsf/router/request_file_system_handler.e
Jocelyn Fiat 5abc79b7c3 Nino connector:
- fixed issue related to `ready_for_reading'  now use the `try_...' variant
 - for now Nino does not support persistent connection, then we have to respond with "Connection: close"

REQUEST_FILE_SYSTEM_HANDLER:
 - added not_found_handler and access_denied_handler, so that the user can customize related response

WSF_REQUEST and WSF_VALUE:
 - modified how uploaded file are handled, fixed various issues, and added WSF_UPLOADED_FILE (it is a WSF_VALUE)

WSF_VALUE:
 - added change_name (a_name: like name)
 - added url_encoded_name to other WSF_values

WSF_REQUEST:
 - added `destroy' to perform end of request cleaning (such as deleting temp uploaded files)
 - renamed `raw_post_data_recorded' as `raw_input_data_recorded', and related feature
 - do not store the RAW_POST_DATA in meta variable anymore, but in WSF_REQUEST.raw_input_data is asked

Added WSF_HTML_PAGE_RESPONSE to help user

WSF_REPONSE.redirect_... now use "temp_redirect" as default
  instead of "moved_permanently" which is specific usage

Removed many obsolete features.
2012-03-13 18:07:28 +01:00

349 lines
8.0 KiB
Plaintext

note
description: "[
Request handler used to respond file system request.
]"
date: "$Date$"
revision: "$Revision$"
class
REQUEST_FILE_SYSTEM_HANDLER [C -> REQUEST_HANDLER_CONTEXT]
inherit
REQUEST_HANDLER [C]
create
make
feature {NONE} -- Initialization
make (a_root: READABLE_STRING_8)
require
a_root_exists: node_exists (a_root)
do
document_root := a_root
end
feature -- Access
document_root: READABLE_STRING_8
-- Document root for the file system
directory_index: detachable ARRAY [READABLE_STRING_8]
-- File serve if a directory index is requested
not_found_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
access_denied_handler: detachable PROCEDURE [ANY, TUPLE [uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]
feature -- Element change
set_directory_index (idx: like directory_index)
-- Set `directory_index' as `idx'
do
if idx = Void or else idx.is_empty then
directory_index := Void
else
directory_index := idx
end
end
set_not_found_handler (h: like not_found_handler)
-- Set `not_found_handler' to `h'
do
not_found_handler := h
end
set_access_denied_handler (h: like access_denied_handler)
-- Set `access_denied_handler' to `h'
do
access_denied_handler := h
end
feature -- Execution
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
local
h: HTTP_HEADER
s: STRING
uri: STRING
do
if attached {WSF_STRING} ctx.path_parameter ("path") as l_path then
uri := l_path.string
process_uri (uri, ctx, req, res)
else
create h.make
h.put_content_type_text_html
s := "Hello " + ctx.path + "%N"
s.append ("root=" + document_root)
h.put_content_length (s.count)
res.set_status_code ({HTTP_STATUS_CODE}.ok)
res.put_header_text (h.string)
res.put_string (s)
end
end
process_uri (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
f: RAW_FILE
fn: READABLE_STRING_8
do
fn := resource_filename (uri)
create f.make (fn)
if f.exists then
if f.is_readable then
if f.is_directory then
respond_index (req.request_uri, fn, ctx, req, res)
else
respond_file (f, ctx, req, res)
end
else
respond_access_denied (uri, ctx, req, res)
end
else
respond_not_found (uri, ctx, req, res)
end
end
respond_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
h: HTTP_HEADER
uri, s: STRING_8
d: DIRECTORY
l_files: LIST [STRING_8]
do
create d.make_open_read (dn)
if attached directory_index_file (d) as f then
respond_file (f, ctx, req, res)
else
uri := a_uri
if not uri.is_empty and then uri [uri.count] /= '/' then
uri.append_character ('/')
end
s := "[
<html>
<head>
<title>Index for folder: $URI</title>
</head>
<body>
<h1>Index for $URI</h1>
<ul>
]"
s.replace_substring_all ("$URI", uri)
from
l_files := d.linear_representation
l_files.start
until
l_files.after
loop
s.append ("<li><a href=%"" + uri + l_files.item_for_iteration + "%">" + l_files.item_for_iteration + "</a></li>%N")
l_files.forth
end
s.append ("[
</ul>
</body>
</html>
]"
)
create h.make
h.put_content_type_text_html
res.set_status_code ({HTTP_STATUS_CODE}.ok)
h.put_content_length (s.count)
res.put_header_text (h.string)
if not req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head) then
res.put_string (s)
end
res.flush
end
d.close
end
respond_file (f: FILE; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
ext: READABLE_STRING_8
ct: detachable READABLE_STRING_8
fres: WSF_FILE_RESPONSE
do
ext := extension (f.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.name)
fres.set_status_code ({HTTP_STATUS_CODE}.ok)
fres.set_answer_head_request_method (req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head))
res.put_response (fres)
end
respond_not_found (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
h: HTTP_HEADER
s: STRING_8
do
if attached not_found_handler as hdl then
hdl.call ([uri, ctx, req, res])
else
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%" not found%N")
res.set_status_code ({HTTP_STATUS_CODE}.not_found)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
end
end
respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
h: HTTP_HEADER
s: STRING_8
do
if attached access_denied_handler as hdl then
hdl.call ([uri, ctx, req, res])
else
create h.make
h.put_content_type_text_plain
create s.make_empty
s.append ("Resource %"" + uri + "%": Access denied%N")
res.set_status_code ({HTTP_STATUS_CODE}.forbidden)
h.put_content_length (s.count)
res.put_header_text (h.string)
res.put_string (s)
res.flush
end
end
feature {NONE} -- Implementation
directory_index_file (d: DIRECTORY): detachable FILE
local
f: detachable RAW_FILE
fn: FILE_NAME
do
if attached directory_index as default_index then
across
default_index as c
until
Result /= Void
loop
if d.has_entry (c.item) then
create fn.make_from_string (d.name)
fn.set_file_name (c.item)
if f = Void then
create f.make (fn.string)
else
f.make (fn.string)
end
if f.exists and then f.is_readable then
Result := f
end
end
end
end
end
resource_filename (uri: READABLE_STRING_8): READABLE_STRING_8
do
Result := real_filename (document_root + real_filename (uri))
end
dirname (uri: READABLE_STRING_8): READABLE_STRING_8
local
p: INTEGER
do
p := uri.last_index_of ('/', uri.count)
if p > 0 then
Result := uri.substring (1, p - 1)
else
create {STRING_8} Result.make_empty
end
end
filename (uri: READABLE_STRING_8): READABLE_STRING_8
local
p: INTEGER
do
p := uri.last_index_of ('/', uri.count)
if p > 0 then
Result := uri.substring (p + 1, uri.count)
else
Result := uri.twin
end
end
extension (uri: READABLE_STRING_8): READABLE_STRING_8
local
p: INTEGER
do
p := uri.last_index_of ('.', uri.count)
if p > 0 then
Result := uri.substring (p + 1, uri.count)
else
create {STRING_8} Result.make_empty
end
end
real_filename (fn: STRING): STRING
-- Real filename from url-path `fn'
--| Find a better design for this piece of code
--| Eventually in a spec/$ISE_PLATFORM/ specific cluster
do
if fn.is_empty then
Result := fn
else
if {PLATFORM}.is_windows then
create Result.make_from_string (fn)
Result.replace_substring_all ("/", "\")
if Result [Result.count] = '\' then
Result.remove_tail (1)
end
else
Result := fn
if Result [Result.count] = '/' then
Result.remove_tail (1)
end
end
end
end
feature {NONE} -- Implementation
node_exists (p: READABLE_STRING_8): BOOLEAN
local
f: RAW_FILE
do
create f.make (p)
Result := f.exists
end
extension_mime_mapping: HTTP_FILE_EXTENSION_MIME_MAPPING
local
f: RAW_FILE
once
create f.make ("mime.types")
if f.exists and then f.is_readable then
create Result.make_from_file (f.name)
else
create Result.make_default
end
end
note
copyright: "2011-2011, 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