Added to WSF_REQUEST
- raw_header_data: like meta_string_variable - read_input_data_into (buf: STRING) - is_content_type_accepted (a_content_type: READABLE_STRING_GENERAL): BOOLEAN Changed raw_input_data to return IMMUTABLE_STRING_8 Added WSF_METHOD_NOT_ALLOWED_RESPONSE Added WSF_TRACE_RESPONSE to respond TRACE request Now Not_found response return html content if the client accepts, other text/plain Implemented TRACE response, and Method not allowed as implementation of WSF_ROUTED_SERVICE.execute_default
This commit is contained in:
@@ -48,10 +48,23 @@ feature -- Execution
|
||||
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Default procedure
|
||||
local
|
||||
msg: WSF_RESPONSE_MESSAGE
|
||||
not_found: WSF_NOT_FOUND_RESPONSE
|
||||
not_allowed: WSF_METHOD_NOT_ALLOWED_RESPONSE
|
||||
trace: WSF_TRACE_RESPONSE
|
||||
do
|
||||
create not_found.make (req)
|
||||
res.send (not_found)
|
||||
if req.is_request_method ({HTTP_REQUEST_METHODS}.method_trace) then
|
||||
create trace.make (req)
|
||||
msg := trace
|
||||
elseif attached router.allowed_methods_for_request (req) as mtds and then not mtds.is_empty then
|
||||
create not_allowed.make (req)
|
||||
not_allowed.set_suggested_methods (mtds)
|
||||
msg := not_allowed
|
||||
else
|
||||
create not_found.make (req)
|
||||
msg := not_found
|
||||
end
|
||||
res.send (msg)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
@@ -207,6 +207,31 @@ feature -- Status report
|
||||
end
|
||||
end
|
||||
|
||||
allowed_methods_for_request (req: WSF_REQUEST): WSF_ROUTER_METHODS
|
||||
-- Allowed methods for `req'
|
||||
local
|
||||
m: WSF_ROUTER_MAPPING
|
||||
l_rqsmethods: detachable WSF_ROUTER_METHODS
|
||||
do
|
||||
create Result
|
||||
|
||||
across
|
||||
mappings as c
|
||||
loop
|
||||
m := c.item.mapping
|
||||
if attached {WSF_ROUTING_HANDLER} m.handler as l_routing then
|
||||
l_rqsmethods := l_routing.router.allowed_methods_for_request (req)
|
||||
elseif m.is_mapping (req, Current) then
|
||||
l_rqsmethods := c.item.request_methods
|
||||
else
|
||||
l_rqsmethods := Void
|
||||
end
|
||||
if l_rqsmethods /= Void then
|
||||
Result := Result + l_rqsmethods
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Hook
|
||||
|
||||
execute_before (a_mapping: WSF_ROUTER_MAPPING)
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
note
|
||||
description: "[
|
||||
This class is used to report a 405 Method not allowed response
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_METHOD_NOT_ALLOWED_RESPONSE
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
SHARED_HTML_ENCODER
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (req: WSF_REQUEST)
|
||||
do
|
||||
request := req
|
||||
create header.make
|
||||
create suggested_methods
|
||||
end
|
||||
|
||||
feature -- Header
|
||||
|
||||
header: HTTP_HEADER
|
||||
-- Response' header
|
||||
|
||||
request: WSF_REQUEST
|
||||
-- Associated request.
|
||||
|
||||
suggested_methods: WSF_ROUTER_METHODS
|
||||
-- Optional suggestions
|
||||
-- First is the default.
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_suggested_methods (m: like suggested_methods)
|
||||
-- Set `suggested_methods' to `m'
|
||||
do
|
||||
suggested_methods := m
|
||||
end
|
||||
|
||||
feature {WSF_RESPONSE} -- Output
|
||||
|
||||
send_to (res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING
|
||||
l_title: detachable READABLE_STRING_GENERAL
|
||||
h: like header
|
||||
do
|
||||
h := header
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
|
||||
s := "Not allowed"
|
||||
|
||||
if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then
|
||||
s := "<html><head>"
|
||||
s.append ("<title>")
|
||||
s.append (html_encoder.encoded_string (request.request_uri))
|
||||
s.append ("Error 405 (Method Not Allowed)!!")
|
||||
s.append ("</title>%N")
|
||||
s.append (
|
||||
"[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#suggestions { margin: auto; width: 60%;}
|
||||
div#suggestions ul { }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
div#logo div.outter div.inner2 { margin: 10px 15px; width: 30px; height: 15px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">Error 405 (Method Not Allowed)!!</div>
|
||||
]")
|
||||
s.append ("<div id=%"logo%">")
|
||||
s.append ("<div class=%"outter%"> ")
|
||||
s.append ("<div class=%"inner1%"></div>")
|
||||
s.append ("<div class=%"inner2%"></div>")
|
||||
s.append ("</div>")
|
||||
s.append ("Error 405 (Method Not Allowed)</div>")
|
||||
s.append ("<div id=%"message%">Error 405 (Method Not Allowed): the request method <code>")
|
||||
s.append (request.request_method)
|
||||
s.append ("</code> is inappropriate for the URL for <code>" + html_encoder.encoded_string (request.request_uri) + "</code>.</div>")
|
||||
if attached suggested_methods as lst and then not lst.is_empty then
|
||||
s.append ("<div id=%"suggestions%"><strong>Allowed methods:</strong>")
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
s.append (" ")
|
||||
s.append (c.item)
|
||||
end
|
||||
s.append ("%N")
|
||||
end
|
||||
s.append ("<div id=%"footer%"></div>")
|
||||
s.append ("</body>%N")
|
||||
s.append ("</html>%N")
|
||||
|
||||
h.put_content_type_text_html
|
||||
else
|
||||
s := "Error 405 (Method Not Allowed): the request method "
|
||||
s.append (request.request_method)
|
||||
s.append (" is inappropriate for the URL for '" + html_encoder.encoded_string (request.request_uri) + "'.%N")
|
||||
if attached suggested_methods as lst and then not lst.is_empty then
|
||||
s.append ("Allowed methods:")
|
||||
across
|
||||
lst as c
|
||||
loop
|
||||
s.append (" ")
|
||||
s.append (c.item)
|
||||
end
|
||||
s.append ("%N")
|
||||
end
|
||||
h.put_content_type_text_plain
|
||||
end
|
||||
h.put_content_length (s.count)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
res.flush
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, 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
|
||||
@@ -8,7 +8,6 @@ note
|
||||
class
|
||||
WSF_NOT_FOUND_RESPONSE
|
||||
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
@@ -57,59 +56,85 @@ feature {WSF_RESPONSE} -- Output
|
||||
h := header
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.not_found)
|
||||
|
||||
s := "<html><head>"
|
||||
s.append ("<title>")
|
||||
s.append (html_encoder.encoded_string (request.request_uri))
|
||||
s.append (" - 404 Not Found")
|
||||
s.append ("</title>%N")
|
||||
s.append ("[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#suggestions { margin: auto; width: 60%;}
|
||||
div#suggestions ul { }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
div#logo div.outter div.inner2 { margin: 10px 15px; width: 30px; height: 15px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">404 Not Found</div>
|
||||
]")
|
||||
s.append ("<div id=%"logo%">")
|
||||
s.append ("<div class=%"outter%"> ")
|
||||
s.append ("<div class=%"inner1%"></div>")
|
||||
s.append ("<div class=%"inner2%"></div>")
|
||||
s.append ("</div>")
|
||||
s.append ("404 Not Found</div>")
|
||||
s.append ("<div id=%"message%">404 Not Found: <code>" + html_encoder.encoded_string (request.request_uri) + "</code></div>")
|
||||
if attached suggested_locations as lst and then not lst.is_empty then
|
||||
s.append ("<div id=%"suggestions%"><strong>Perhaps your are looking for:</strong><ul>")
|
||||
from
|
||||
lst.start
|
||||
until
|
||||
lst.after
|
||||
loop
|
||||
s.append ("<li>")
|
||||
l_title := lst.item.title
|
||||
if l_title = Void then
|
||||
l_title := lst.item.location
|
||||
if request.is_content_type_accepted ({HTTP_MIME_TYPES}.text_html) then
|
||||
s := "<html lang=%"en%"><head>"
|
||||
s.append ("<title>")
|
||||
s.append (html_encoder.encoded_string (request.request_uri))
|
||||
s.append ("Error 404 (Not Found)")
|
||||
s.append ("</title>%N")
|
||||
s.append ("[
|
||||
<style type="text/css">
|
||||
div#header {color: #fff; background-color: #000; padding: 20px; width: 100%; text-align: center; font-size: 2em; font-weight: bold;}
|
||||
div#message { margin: 40px; width: 100%; text-align: center; font-size: 1.5em; }
|
||||
div#suggestions { margin: auto; width: 60%;}
|
||||
div#suggestions ul { }
|
||||
div#footer {color: #999; background-color: #eee; padding: 10px; width: 100%; text-align: center; }
|
||||
div#logo { float: right; margin: 20px; width: 60px height: auto; font-size: 0.8em; text-align: center; }
|
||||
div#logo div.outter { padding: 6px; width: 60px; border: solid 3px #500; background-color: #b00;}
|
||||
div#logo div.outter div.inner1 { display: block; margin: 10px 15px; width: 30px; height: 50px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
div#logo div.outter div.inner2 { margin: 10px 15px; width: 30px; height: 15px; color: #fff; background-color: #fff; border: solid 2px #900; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">Error 404 (Not Found)</div>
|
||||
]")
|
||||
s.append ("<div id=%"logo%">")
|
||||
s.append ("<div class=%"outter%"> ")
|
||||
s.append ("<div class=%"inner1%"></div>")
|
||||
s.append ("<div class=%"inner2%"></div>")
|
||||
s.append ("</div>")
|
||||
s.append ("Error 404 (Not Found)</div>")
|
||||
s.append ("<div id=%"message%">Error 404 (Not Found): <code>" + html_encoder.encoded_string (request.request_uri) + "</code></div>")
|
||||
if attached suggested_locations as lst and then not lst.is_empty then
|
||||
s.append ("<div id=%"suggestions%"><strong>Perhaps your are looking for:</strong><ul>")
|
||||
from
|
||||
lst.start
|
||||
until
|
||||
lst.after
|
||||
loop
|
||||
s.append ("<li>")
|
||||
l_title := lst.item.title
|
||||
if l_title = Void then
|
||||
l_title := lst.item.location
|
||||
end
|
||||
s.append ("<a href=%"" + lst.item.location + "%">" + html_encoder.encoded_string (l_title.to_string_32) + "</a>")
|
||||
s.append ("</li>%N")
|
||||
|
||||
lst.forth
|
||||
end
|
||||
s.append ("<a href=%"" + lst.item.location + "%">" + html_encoder.encoded_string (l_title.to_string_32) + "</a>")
|
||||
s.append ("</li>%N")
|
||||
|
||||
lst.forth
|
||||
s.append ("</ul></div>%N")
|
||||
end
|
||||
s.append ("</ul></div>%N")
|
||||
end
|
||||
s.append ("<div id=%"footer%"></div>")
|
||||
s.append ("</body>%N")
|
||||
s.append ("</html>%N")
|
||||
s.append ("<div id=%"footer%"></div>")
|
||||
s.append ("</body>%N")
|
||||
s.append ("</html>%N")
|
||||
|
||||
h.put_content_type_text_html
|
||||
else
|
||||
s := "Error 404 (Not Found): "
|
||||
s.append (request.request_uri)
|
||||
s.append_character ('%N')
|
||||
if attached suggested_locations as lst and then not lst.is_empty then
|
||||
s.append ("%NPerhaps your are looking for:%N")
|
||||
from
|
||||
lst.start
|
||||
until
|
||||
lst.after
|
||||
loop
|
||||
s.append (" - ")
|
||||
l_title := lst.item.title
|
||||
if l_title = Void then
|
||||
l_title := lst.item.location
|
||||
end
|
||||
s.append (lst.item.location)
|
||||
s.append ("%N")
|
||||
|
||||
lst.forth
|
||||
end
|
||||
end
|
||||
|
||||
h.put_content_type_text_plain
|
||||
end
|
||||
h.put_content_length (s.count)
|
||||
h.put_content_type_text_html
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
res.flush
|
||||
|
||||
97
library/server/wsf/src/response/wsf_trace_response.e
Normal file
97
library/server/wsf/src/response/wsf_trace_response.e
Normal file
@@ -0,0 +1,97 @@
|
||||
note
|
||||
description: "[
|
||||
This class is used to respond a TRACE request
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_TRACE_RESPONSE
|
||||
|
||||
inherit
|
||||
WSF_RESPONSE_MESSAGE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (req: WSF_REQUEST)
|
||||
do
|
||||
request := req
|
||||
create header.make
|
||||
end
|
||||
|
||||
feature -- Header
|
||||
|
||||
header: HTTP_HEADER
|
||||
-- Response' header
|
||||
|
||||
request: WSF_REQUEST
|
||||
-- Associated request.
|
||||
|
||||
feature {WSF_RESPONSE} -- Output
|
||||
|
||||
send_to (res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING
|
||||
l_title: detachable READABLE_STRING_GENERAL
|
||||
h: like header
|
||||
req: like request
|
||||
n, nb: INTEGER
|
||||
do
|
||||
h := header
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||
req := request
|
||||
if attached req.raw_header_data as l_header then
|
||||
create s.make (l_header.count)
|
||||
s.append (l_header.to_string_8)
|
||||
s.append_character ('%N')
|
||||
else
|
||||
s := ""
|
||||
end
|
||||
if req.is_chunked_input then
|
||||
h.put_transfer_encoding_chunked
|
||||
res.put_header_text (h.string)
|
||||
res.put_chunk (s, Void)
|
||||
if attached req.input as l_input then
|
||||
|
||||
from
|
||||
n := 1_024
|
||||
until
|
||||
n = 0
|
||||
loop
|
||||
s.wipe_out
|
||||
nb := l_input.read_to_string (s, 1, n)
|
||||
if nb = 0 then
|
||||
n := 0
|
||||
else
|
||||
if nb < n then
|
||||
n := 0
|
||||
end
|
||||
res.put_chunk (s, Void)
|
||||
end
|
||||
end
|
||||
end
|
||||
res.put_chunk_end
|
||||
res.flush
|
||||
else
|
||||
req.read_input_data_into (s)
|
||||
h.put_content_length (s.count)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
res.flush
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, 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
|
||||
@@ -144,12 +144,26 @@ feature -- Setting
|
||||
|
||||
feature -- Raw input data
|
||||
|
||||
raw_input_data: detachable READABLE_STRING_8
|
||||
raw_input_data: detachable IMMUTABLE_STRING_8
|
||||
-- Raw input data is `raw_input_data_recorded' is True
|
||||
|
||||
set_raw_input_data (d: READABLE_STRING_8)
|
||||
do
|
||||
raw_input_data := d
|
||||
if attached {IMMUTABLE_STRING_8} d as imm then
|
||||
raw_input_data := d
|
||||
else
|
||||
create raw_input_data.make_from_string (d)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Raw header data
|
||||
|
||||
raw_header_data: like meta_string_variable
|
||||
-- Raw header data if available.
|
||||
do
|
||||
Result := meta_string_variable ("RAW_HEADER_DATA")
|
||||
ensure
|
||||
is_valid_as_string_8: Result /= Void implies Result.is_valid_as_string_8
|
||||
end
|
||||
|
||||
feature -- Error handling
|
||||
@@ -178,6 +192,48 @@ feature -- Access: Input
|
||||
Result := wgi_request.is_chunked_input
|
||||
end
|
||||
|
||||
read_input_data_into (buf: STRING)
|
||||
-- retrieve the content from the `input' stream into `s'
|
||||
-- warning: if the input data has already been retrieved
|
||||
-- you might not get anything
|
||||
local
|
||||
l_input: WGI_INPUT_STREAM
|
||||
n: INTEGER
|
||||
s: STRING
|
||||
do
|
||||
if raw_input_data_recorded and then attached raw_input_data as d then
|
||||
buf.copy (d)
|
||||
else
|
||||
l_input := input
|
||||
if is_chunked_input then
|
||||
from
|
||||
n := 1_024
|
||||
until
|
||||
n = 0
|
||||
loop
|
||||
l_input.read_string (n)
|
||||
s := l_input.last_string
|
||||
if s.count = 0 then
|
||||
n := 0
|
||||
else
|
||||
if s.count < n then
|
||||
n := 0
|
||||
end
|
||||
buf.append (s)
|
||||
end
|
||||
end
|
||||
else
|
||||
n := content_length_value.as_integer_32
|
||||
buf.resize (buf.count + n)
|
||||
n := l_input.read_to_string (buf, buf.count + 1, n)
|
||||
check n = content_length_value.as_integer_32 end
|
||||
end
|
||||
if raw_input_data_recorded then
|
||||
set_raw_input_data (buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Helper
|
||||
|
||||
is_request_method (m: READABLE_STRING_GENERAL): BOOLEAN
|
||||
@@ -198,6 +254,14 @@ feature -- Helper
|
||||
Result := request_method.is_case_insensitive_equal ({HTTP_REQUEST_METHODS}.method_get)
|
||||
end
|
||||
|
||||
is_content_type_accepted (a_content_type: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Does client accepts content_type for the response?
|
||||
do
|
||||
if attached http_accept as l_accept then
|
||||
Result := l_accept.has_substring (a_content_type)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Eiffel WGI access
|
||||
|
||||
wgi_version: READABLE_STRING_8
|
||||
|
||||
Reference in New Issue
Block a user