diff --git a/library/server/wsf/router/wsf_routed_service.e b/library/server/wsf/router/wsf_routed_service.e
index 00dd52ab..9f201eed 100644
--- a/library/server/wsf/router/wsf_routed_service.e
+++ b/library/server/wsf/router/wsf_routed_service.e
@@ -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
diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e
index c47f03f3..c3db762e 100644
--- a/library/server/wsf/router/wsf_router.e
+++ b/library/server/wsf/router/wsf_router.e
@@ -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)
diff --git a/library/server/wsf/src/response/wsf_method_not_allowed_response.e b/library/server/wsf/src/response/wsf_method_not_allowed_response.e
new file mode 100644
index 00000000..6b99b59b
--- /dev/null
+++ b/library/server/wsf/src/response/wsf_method_not_allowed_response.e
@@ -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 := "
"
+ s.append ("Allowed methods:")
+ across
+ lst as c
+ loop
+ s.append (" ")
+ s.append (c.item)
+ end
+ s.append ("%N")
+ end
+ s.append ("")
+ s.append ("%N")
+ s.append ("%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
diff --git a/library/server/wsf/src/response/wsf_not_found_response.e b/library/server/wsf/src/response/wsf_not_found_response.e
index 3a17cf0f..0f6ecc5c 100644
--- a/library/server/wsf/src/response/wsf_not_found_response.e
+++ b/library/server/wsf/src/response/wsf_not_found_response.e
@@ -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 := ""
- s.append ("
")
- s.append (html_encoder.encoded_string (request.request_uri))
- s.append (" - 404 Not Found")
- s.append ("%N")
- s.append ("[
-
-
-
-
- ]")
- s.append ("
")
- s.append ("
")
- s.append ("
")
- s.append ("
")
- s.append ("
")
- s.append ("404 Not Found
")
- s.append ("
404 Not Found: " + html_encoder.encoded_string (request.request_uri) + "
")
- if attached suggested_locations as lst and then not lst.is_empty then
- s.append ("
Perhaps your are looking for: %N")
- end
- s.append ("")
- s.append ("%N")
- s.append ("%N")
+ s.append ("")
+ s.append ("%N")
+ s.append ("%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
diff --git a/library/server/wsf/src/response/wsf_trace_response.e b/library/server/wsf/src/response/wsf_trace_response.e
new file mode 100644
index 00000000..d3446956
--- /dev/null
+++ b/library/server/wsf/src/response/wsf_trace_response.e
@@ -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
diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e
index ad31a9dc..99e5d22a 100644
--- a/library/server/wsf/src/wsf_request.e
+++ b/library/server/wsf/src/wsf_request.e
@@ -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