Added HTTP_FILE_EXTENSION_MIME_MAPPING
Added REQUEST_FILE_SYSTEM_HANDLER to the router library Added file system handler in "hello_routed_world" example
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
EIFGENs
|
EIFGENs
|
||||||
tests/temp/
|
tests/temp/
|
||||||
|
.svn/
|
||||||
|
|||||||
9
examples/hello_routed_world/htdocs/dft/index.html
Normal file
9
examples/hello_routed_world/htdocs/dft/index.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hello Eiffel::default</title>
|
||||||
|
<link rel="stylesheet" href="../style.css" type="text/css" media="all" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello Eiffel Default World</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
examples/hello_routed_world/htdocs/home.html
Normal file
9
examples/hello_routed_world/htdocs/home.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hello Eiffel</title>
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" media="all" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello Eiffel World :D</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
examples/hello_routed_world/htdocs/htdocs.zip
Normal file
BIN
examples/hello_routed_world/htdocs/htdocs.zip
Normal file
Binary file not shown.
1
examples/hello_routed_world/htdocs/style.css
Normal file
1
examples/hello_routed_world/htdocs/style.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
h1 { border: solid 1px #00f; margin: 5px; padding: 5px; }
|
||||||
1479
examples/hello_routed_world/mime.types
Normal file
1479
examples/hello_routed_world/mime.types
Normal file
File diff suppressed because it is too large
Load Diff
@@ -37,8 +37,13 @@ feature {NONE} -- Initialization
|
|||||||
local
|
local
|
||||||
ra: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
ra: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||||
hello: REQUEST_URI_TEMPLATE_ROUTING_HANDLER
|
hello: REQUEST_URI_TEMPLATE_ROUTING_HANDLER
|
||||||
|
www: REQUEST_FILE_SYSTEM_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
|
||||||
do
|
do
|
||||||
router.map_agent ("/home", agent execute_home)
|
router.map_agent ("/home", agent execute_home)
|
||||||
|
create www.make (document_root)
|
||||||
|
www.set_directory_index (<<"index.html">>)
|
||||||
|
|
||||||
|
router.map ("/www{/path}{?query}", www)
|
||||||
|
|
||||||
--| Map all "/hello*" using a ROUTING_HANDLER
|
--| Map all "/hello*" using a ROUTING_HANDLER
|
||||||
create hello.make (3)
|
create hello.make (3)
|
||||||
@@ -60,6 +65,21 @@ feature {NONE} -- Initialization
|
|||||||
router.map_agent_with_request_methods ("/method/custom", agent handle_method_post, <<"POST">>)
|
router.map_agent_with_request_methods ("/method/custom", agent handle_method_post, <<"POST">>)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
document_root: READABLE_STRING_8
|
||||||
|
local
|
||||||
|
e: EXECUTION_ENVIRONMENT
|
||||||
|
dn: DIRECTORY_NAME
|
||||||
|
once
|
||||||
|
create e
|
||||||
|
create dn.make_from_string (e.current_working_directory)
|
||||||
|
dn.extend ("htdocs")
|
||||||
|
Result := dn.string
|
||||||
|
if Result[Result.count] = Operating_environment.directory_separator then
|
||||||
|
Result := Result.substring (1, Result.count - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Execution
|
feature -- Execution
|
||||||
|
|
||||||
execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||||
<assertions precondition="true"/>
|
<assertions precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" full_class_checking="true">
|
<option warning="true" full_class_checking="true" syntax="provisional">
|
||||||
<assertions precondition="true"/>
|
<assertions precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
|||||||
240
library/protocol/http/src/http_file_extension_mime_mapping.e
Normal file
240
library/protocol/http/src/http_file_extension_mime_mapping.e
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Various common MIME types for file extensions
|
||||||
|
|
||||||
|
See also for longer list and description
|
||||||
|
http://www.webmaster-toolkit.com/mime-types.shtml
|
||||||
|
|
||||||
|
Please suggest missing entries
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_FILE_EXTENSION_MIME_MAPPING
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ANY
|
||||||
|
|
||||||
|
HTTP_MIME_TYPES
|
||||||
|
export
|
||||||
|
{NONE} all
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_empty,
|
||||||
|
make_default,
|
||||||
|
make_from_string,
|
||||||
|
make_from_file
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_empty (n: INTEGER)
|
||||||
|
-- Create with no mapping
|
||||||
|
-- but one can use `map' to add new mapping
|
||||||
|
do
|
||||||
|
create mapping.make (n)
|
||||||
|
mapping.compare_objects
|
||||||
|
end
|
||||||
|
|
||||||
|
make_default
|
||||||
|
-- Create with default limited mapping
|
||||||
|
-- One can use `map' to add new mapping
|
||||||
|
local
|
||||||
|
m: like mapping
|
||||||
|
do
|
||||||
|
create m.make (40)
|
||||||
|
mapping := m
|
||||||
|
m.compare_objects
|
||||||
|
m.force (text_css, "css")
|
||||||
|
m.force (text_html, "html")
|
||||||
|
m.force (text_xml, "xml")
|
||||||
|
m.force (application_json, "json")
|
||||||
|
m.force (application_javascript, "js")
|
||||||
|
m.force (application_rss_xml, "rss")
|
||||||
|
m.force (application_atom_xml, "atom")
|
||||||
|
m.force (image_x_ico, "ico")
|
||||||
|
m.force (image_gif, "gif")
|
||||||
|
m.force (image_jpeg, "jpeg")
|
||||||
|
m.force (image_jpg, "jpg")
|
||||||
|
m.force (image_png, "png")
|
||||||
|
m.force (application_zip, "zip")
|
||||||
|
m.force (application_x_bzip, "bz")
|
||||||
|
m.force (application_x_bzip2, "bz2")
|
||||||
|
m.force (application_x_gzip, "gz")
|
||||||
|
m.force (application_x_gzip, "gzip")
|
||||||
|
m.force (application_x_tar, "tar")
|
||||||
|
m.force (application_x_compressed, "tgz")
|
||||||
|
m.force (application_postscript, "ps")
|
||||||
|
m.force (application_pdf, "pdf")
|
||||||
|
m.force (application_x_shockwave_flash, "swf")
|
||||||
|
m.force (text_plain, "conf")
|
||||||
|
m.force (text_plain, "log")
|
||||||
|
m.force (text_plain, "text")
|
||||||
|
m.force (text_plain, "txt")
|
||||||
|
end
|
||||||
|
|
||||||
|
make_from_file (fn: READABLE_STRING_8)
|
||||||
|
-- Create with mime.types file
|
||||||
|
-- One can use `map' to add new mapping
|
||||||
|
local
|
||||||
|
f: RAW_FILE
|
||||||
|
s: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
create f.make (fn)
|
||||||
|
if f.exists and then f.is_readable then
|
||||||
|
make_empty (50)
|
||||||
|
f.open_read
|
||||||
|
from
|
||||||
|
f.read_line
|
||||||
|
until
|
||||||
|
f.exhausted or f.end_of_file
|
||||||
|
loop
|
||||||
|
add_mapping_line (f.last_string)
|
||||||
|
f.read_line
|
||||||
|
end
|
||||||
|
f.close
|
||||||
|
else
|
||||||
|
make_empty (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
make_from_string (t: READABLE_STRING_8)
|
||||||
|
-- Set mapping from multiline string `t'
|
||||||
|
-- line should be formatted as in http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
|
||||||
|
--| # is a comment
|
||||||
|
--| mime-type space(s) extensions
|
||||||
|
local
|
||||||
|
i,j,n: INTEGER
|
||||||
|
do
|
||||||
|
make_empty (10)
|
||||||
|
n := t.count
|
||||||
|
if n > 0 then
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
until
|
||||||
|
i = 0 or i > n
|
||||||
|
loop
|
||||||
|
j := t.index_of ('%N', i)
|
||||||
|
if j > 0 then
|
||||||
|
add_mapping_line (t.substring (i, j - 1))
|
||||||
|
i := j + 1
|
||||||
|
else
|
||||||
|
add_mapping_line (t.substring (i, n))
|
||||||
|
i := 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
mime_type (ext: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||||
|
-- Mime type for extension `ext'
|
||||||
|
do
|
||||||
|
Result := mapping.item (ext.as_lower)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
map (e: READABLE_STRING_8; t: READABLE_STRING_8)
|
||||||
|
-- Add mapping extension `e' to mime type `t'
|
||||||
|
do
|
||||||
|
mapping.force (t, e.as_lower)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
add_mapping_line (t: READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
i,j,n: INTEGER
|
||||||
|
l_type, l_ext: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
n := t.count
|
||||||
|
if n > 0 then
|
||||||
|
-- ignore blanks
|
||||||
|
i := next_non_blank_position (t, i)
|
||||||
|
if i > 0 then
|
||||||
|
if t[i] = '#' then
|
||||||
|
--| ignore
|
||||||
|
else
|
||||||
|
j := next_blank_position (t, i)
|
||||||
|
if j > i then
|
||||||
|
l_type := t.substring (i, j - 1)
|
||||||
|
from
|
||||||
|
until
|
||||||
|
i = 0
|
||||||
|
loop
|
||||||
|
i := next_non_blank_position (t, j)
|
||||||
|
if i > 0 then
|
||||||
|
j := next_blank_position (t, i)
|
||||||
|
if j = 0 then
|
||||||
|
l_ext := t.substring (i, n)
|
||||||
|
i := 0
|
||||||
|
else
|
||||||
|
l_ext := t.substring (i, j - 1)
|
||||||
|
i := j
|
||||||
|
end
|
||||||
|
map (l_ext, l_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next_blank_position (s: READABLE_STRING_8; p: INTEGER): INTEGER
|
||||||
|
local
|
||||||
|
i, n: INTEGER
|
||||||
|
do
|
||||||
|
n := s.count
|
||||||
|
from
|
||||||
|
i := p + 1
|
||||||
|
until
|
||||||
|
i > n or s[i].is_space
|
||||||
|
loop
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
if i <= n then
|
||||||
|
Result := i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next_non_blank_position (s: READABLE_STRING_8; p: INTEGER): INTEGER
|
||||||
|
local
|
||||||
|
i, n: INTEGER
|
||||||
|
do
|
||||||
|
n := s.count
|
||||||
|
from
|
||||||
|
i := p + 1
|
||||||
|
until
|
||||||
|
i > n or not s[i].is_space
|
||||||
|
loop
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
if i <= n then
|
||||||
|
Result := i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature {NONE} -- Extension MIME mapping
|
||||||
|
|
||||||
|
mapping: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
||||||
|
|
||||||
|
invariant
|
||||||
|
mapping_keys_are_lowercase: across mapping as c all c.key.same_string (c.key.as_lower) 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
|
||||||
@@ -19,11 +19,7 @@ feature -- Content type : application
|
|||||||
application_atom_xml: STRING = "application/atom+xml"
|
application_atom_xml: STRING = "application/atom+xml"
|
||||||
-- atom application content-type header
|
-- atom application content-type header
|
||||||
|
|
||||||
application_x_www_form_encoded: STRING = "application/x-www-form-urlencoded"
|
application_force_download: STRING = "application/force-download"
|
||||||
-- Starting chars of form url-encoded data content-type header
|
|
||||||
|
|
||||||
application_octet_stream: STRING = "application/octet-stream"
|
|
||||||
-- Octet stream content-type header
|
|
||||||
|
|
||||||
application_javascript: STRING = "application/javascript"
|
application_javascript: STRING = "application/javascript"
|
||||||
-- JavaScript application content-type header
|
-- JavaScript application content-type header
|
||||||
@@ -31,25 +27,54 @@ feature -- Content type : application
|
|||||||
application_json: STRING = "application/json"
|
application_json: STRING = "application/json"
|
||||||
-- JSON application content-type header
|
-- JSON application content-type header
|
||||||
|
|
||||||
|
application_octet_stream: STRING = "application/octet-stream"
|
||||||
|
-- Octet stream content-type header
|
||||||
|
|
||||||
application_pdf: STRING = "application/pdf"
|
application_pdf: STRING = "application/pdf"
|
||||||
-- pdf application content-type header
|
-- pdf application content-type header
|
||||||
|
|
||||||
|
application_postscript: STRING = "application/postscript"
|
||||||
|
-- postscript application content-type header
|
||||||
|
|
||||||
application_rss_xml: STRING = "application/rss+xml"
|
application_rss_xml: STRING = "application/rss+xml"
|
||||||
-- rss application content-type header
|
-- rss application content-type header
|
||||||
|
|
||||||
|
application_rtf: STRING = "application/rtf"
|
||||||
|
-- RTF application content-type header
|
||||||
|
|
||||||
application_xml: STRING = "application/xml"
|
application_xml: STRING = "application/xml"
|
||||||
-- xml application content-type header
|
-- xml application content-type header
|
||||||
|
|
||||||
|
application_x_shockwave_flash: STRING = "application/x-shockwave-flash"
|
||||||
|
|
||||||
application_x_compressed: STRING = "application/x-compressed"
|
application_x_compressed: STRING = "application/x-compressed"
|
||||||
-- x-compressed application content-type header
|
|
||||||
|
application_x_gzip: STRING = "application/x-gzip"
|
||||||
|
|
||||||
application_zip: STRING = "application/zip"
|
application_zip: STRING = "application/zip"
|
||||||
-- ZIP application content-type header
|
|
||||||
|
application_x_bzip: STRING = "application/x-bzip"
|
||||||
|
|
||||||
|
application_x_bzip2: STRING = "application/x-bzip2"
|
||||||
|
|
||||||
|
application_x_tar: STRING = "application/x-tar"
|
||||||
|
|
||||||
|
application_x_www_form_encoded: STRING = "application/x-www-form-urlencoded"
|
||||||
|
-- Starting chars of form url-encoded data content-type header
|
||||||
|
|
||||||
feature -- Content type : audio
|
feature -- Content type : audio
|
||||||
|
|
||||||
|
audio_mpeg3: STRING = "audio/mpeg3"
|
||||||
|
|
||||||
|
audio_mpeg: STRING = "audio/mpeg"
|
||||||
|
|
||||||
|
audio_wav: STRING = "audio/wav"
|
||||||
|
|
||||||
feature -- Content type : image
|
feature -- Content type : image
|
||||||
|
|
||||||
|
image_bmp: STRING = "image/bmp"
|
||||||
|
-- BMP image content-type header
|
||||||
|
|
||||||
image_gif: STRING = "image/gif"
|
image_gif: STRING = "image/gif"
|
||||||
-- GIF image content-type header
|
-- GIF image content-type header
|
||||||
|
|
||||||
@@ -65,6 +90,12 @@ feature -- Content type : image
|
|||||||
image_svg_xml: STRING = "image/svg+xml"
|
image_svg_xml: STRING = "image/svg+xml"
|
||||||
-- SVG+XML image content-type header
|
-- SVG+XML image content-type header
|
||||||
|
|
||||||
|
image_tiff: STRING = "image/tiff"
|
||||||
|
-- TIFF image content-type header
|
||||||
|
|
||||||
|
image_x_ico: STRING = "image/x-ico"
|
||||||
|
-- ICO image content-type header
|
||||||
|
|
||||||
feature -- Content type : message
|
feature -- Content type : message
|
||||||
|
|
||||||
message_http: STRING = "message/http"
|
message_http: STRING = "message/http"
|
||||||
@@ -81,6 +112,8 @@ feature -- Content type : message
|
|||||||
|
|
||||||
feature -- Content type : model
|
feature -- Content type : model
|
||||||
|
|
||||||
|
model_vrml: STRING = "model/vrml"
|
||||||
|
|
||||||
feature -- Content type : multipart
|
feature -- Content type : multipart
|
||||||
|
|
||||||
multipart_mixed: STRING = "multipart/mixed"
|
multipart_mixed: STRING = "multipart/mixed"
|
||||||
@@ -95,6 +128,8 @@ feature -- Content type : multipart
|
|||||||
|
|
||||||
multipart_encrypted: STRING = "multipart/encrypted"
|
multipart_encrypted: STRING = "multipart/encrypted"
|
||||||
|
|
||||||
|
multipart_x_gzip: STRING = "multipart/x-gzip"
|
||||||
|
|
||||||
feature -- Content type : text
|
feature -- Content type : text
|
||||||
|
|
||||||
text_css: STRING = "text/css"
|
text_css: STRING = "text/css"
|
||||||
@@ -119,13 +154,23 @@ feature -- Content type : text
|
|||||||
text_rtf: STRING = "text/rtf"
|
text_rtf: STRING = "text/rtf"
|
||||||
-- rtf content-type header
|
-- rtf content-type header
|
||||||
|
|
||||||
|
text_tab_separated_values: STRING = "text/tab-separated-values"
|
||||||
|
-- TSV text content-type header
|
||||||
|
|
||||||
text_xml: STRING = "text/xml"
|
text_xml: STRING = "text/xml"
|
||||||
-- XML text content-type header
|
-- XML text content-type header
|
||||||
|
|
||||||
text_vcard: STRING = "text/vcard"
|
text_vcard: STRING = "text/vcard"
|
||||||
-- vcard text content-type header
|
-- vcard text content-type header
|
||||||
|
|
||||||
feature -- Content type : video
|
feature -- Content type : video
|
||||||
|
|
||||||
|
video_avi: STRING = "video/avi"
|
||||||
|
|
||||||
|
video_quicktime: STRING = "video/quicktime"
|
||||||
|
|
||||||
|
video_x_motion_jpeg: STRING = "video/x-motion-jpeg"
|
||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2011, Eiffel Software and others"
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ feature -- Methods intented for actions
|
|||||||
|
|
||||||
method_delete: STRING = "DELETE"
|
method_delete: STRING = "DELETE"
|
||||||
-- Deletes the specified resource.
|
-- Deletes the specified resource.
|
||||||
|
|
||||||
feature -- Other Methods
|
feature -- Other Methods
|
||||||
|
|
||||||
method_connect: STRING = "CONNECT"
|
method_connect: STRING = "CONNECT"
|
||||||
|
|||||||
335
library/server/request/router/src/request_file_system_handler.e
Normal file
335
library/server/request/router/src/request_file_system_handler.e
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
-- Execute request handler
|
||||||
|
local
|
||||||
|
h: EWF_HEADER
|
||||||
|
s: STRING
|
||||||
|
uri: STRING
|
||||||
|
do
|
||||||
|
if attached ctx.path_parameter ("path") as l_path then
|
||||||
|
uri := l_path.as_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.write_headers_string (h.string)
|
||||||
|
res.write_string (s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
process_uri (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
h: EWF_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.write_headers_string (h.string)
|
||||||
|
if not req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head) then
|
||||||
|
res.write_string (s)
|
||||||
|
end
|
||||||
|
res.flush
|
||||||
|
end
|
||||||
|
d.close
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_file (f: FILE; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
fn: READABLE_STRING_8
|
||||||
|
h: EWF_HEADER
|
||||||
|
ext: READABLE_STRING_8
|
||||||
|
ct: detachable READABLE_STRING_8
|
||||||
|
do
|
||||||
|
fn := f.name
|
||||||
|
ext := extension (fn)
|
||||||
|
ct := extension_mime_mapping.mime_type (ext)
|
||||||
|
create h.make
|
||||||
|
|
||||||
|
if ct /= Void then
|
||||||
|
h.put_content_type (ct)
|
||||||
|
h.put_content_length (f.count)
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
|
res.write_headers_string (h.string)
|
||||||
|
else
|
||||||
|
create h.make
|
||||||
|
h.put_content_type ({HTTP_MIME_TYPES}.application_force_download)
|
||||||
|
h.put_content_length (f.count)
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
|
res.write_headers_string (h.string)
|
||||||
|
end
|
||||||
|
if not req.request_method.same_string ({HTTP_REQUEST_METHODS}.method_head) then
|
||||||
|
res.write_file_content (fn)
|
||||||
|
end
|
||||||
|
res.flush
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_not_found (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
h: EWF_HEADER
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
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.write_headers_string (h.string)
|
||||||
|
res.write_string (s)
|
||||||
|
res.flush
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
h: EWF_HEADER
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
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.write_headers_string (h.string)
|
||||||
|
res.write_string (s)
|
||||||
|
res.flush
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user