If-Match implemented in skeleton handler

This commit is contained in:
Colin Adams
2013-04-13 14:49:03 +01:00
parent b4ab4875fc
commit 98ad77a57d
6 changed files with 295 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
note
description: "[
Policy-driven helpers to implement processing of GET and HEAD requests.
]"
date: "$Date$"
revision: "$Revision$"
class WSF_GET_HELPER
inherit
WSF_METHOD_HELPER
end

View File

@@ -0,0 +1,80 @@
note
description: "[
Policy-driven helpers to implement a method.
]"
date: "$Date$"
revision: "$Revision$"
deferred class WSF_METHOD_HELPER
feature -- Access
resource_exists: BOOLEAN
-- Does the requested resource (request URI) exist?
feature -- Setting
set_resource_exists
-- Set `resource_exists' to `True'.
do
resource_exists := True
ensure
set: resource_exists
end
feature -- Basic operations
execute_new_resource (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER)
-- Write response to non-existing resource requested by `req.' into `res'.
-- Policy routines are available in `a_handler'.
-- This default implementation does not apply for PUT requests.
-- The behaviour for POST requests depends upon a policy.
require
req_attached: req /= Void
res_attached: res /= Void
a_handler_attached: a_handler /= Void
do
if a_handler.resource_previously_existed (req) then
--| TODO - should we be passing the entire request, or should we further
--| simplify the programmer's task by passing `req.path_translated'?
if a_handler.resource_moved_permanently (req) then
-- TODO 301 Moved Permanently
elseif a_handler.resource_moved_temporarily (req) then
-- TODO 302 Found
else
-- TODO 410 Gone
end
else
-- TODO 404 Not Found
end
end
execute_existing_resource (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER)
-- Write response to existing resource requested by `req.' into `res'.
-- Policy routines are available in `a_handler'.
require
req_attached: req /= Void
res_attached: res /= Void
a_handler_attached: a_handler /= Void
not_if_match_star: attached req.http_if_match as l_if_match implies not l_if_match.same_string ("*")
local
l_etags: LIST [READABLE_STRING_32]
do
if attached req.http_if_match as l_if_match then
l_etags := l_if_match.split (',')
else
-- TODO: check_if_unmodified_since (req, res, a_handler)
end
end
handle_precondition_failed (req: WSF_REQUEST; res: WSF_RESPONSE)
--
require
req_attached: req /= Void
res_attached: res /= Void
do
end
end

View File

@@ -0,0 +1,25 @@
note
description: "[
Default factory for policy-driven method helpers.
Extension methods can be implemented here.
]"
date: "$Date$"
revision: "$Revision$"
class WSF_METHOD_HELPER_FACTORY
feature -- Factory
new_method_helper (a_method: READABLE_STRING_8): detachable WSF_METHOD_HELPER
-- New object for processing `a_method'
require
a_method_attached: a_method /= Void
do
if a_method.is_case_insensitive_equal ({HTTP_REQUEST_METHODS}.method_get) or
a_method.is_case_insensitive_equal ({HTTP_REQUEST_METHODS}.method_head) then
create {WSF_GET_HELPER} Result
end
end
end

View File

@@ -0,0 +1,37 @@
note
description: "[
Default policy for responing to OPTIONS requests other than OPTIONS*
By overriding `execute_options', clients can add a body, for example.
]"
date: "$Date$"
revision: "$Revision$"
class WSF_OPTIONS_POLICY
feature -- Basic operations
execute_options (req: WSF_REQUEST; res: WSF_RESPONSE; a_router: WSF_ROUTER)
-- Write response to `req' into `res'.
require
req_attached: req /= Void
options_request: req.is_request_method ({HTTP_REQUEST_METHODS}.method_options)
res_attached: res /= Void
a_router_attached: a_router /= Void
local
l_methods: WSF_REQUEST_METHODS
h: HTTP_HEADER
do
create h.make
res.set_status_code ({HTTP_STATUS_CODE}.ok)
h.put_content_type ({HTTP_MIME_TYPES}.text_plain)
h.put_current_date
h.put_content_length (0)
l_methods := a_router.allowed_methods_for_request (req)
if not l_methods.is_empty then
h.put_allow (l_methods)
end
res.put_header_text (h.string)
end
end

View File

@@ -0,0 +1,40 @@
note
description: "[
Policies for deciding if a resource that currently doesn't exist used to do so.
This default implementation assumes that no resources used to exist.
]"
date: "$Date$"
revision: "$Revision$"
class WSF_PREVIOUS_POLICY
feature -- Access
resource_previously_existed (req: WSF_REQUEST) : BOOLEAN
-- Did `req.path_translated' exist previously?
require
req_attached: req /= Void
do
-- No. Override if this is not want you want.
end
resource_moved_permanently (req: WSF_REQUEST) : BOOLEAN
-- Was `req.path_translated' moved permanently?
require
req_attached: req /= Void
previously_existed: resource_previously_existed (req)
do
-- No. Override if this is not want you want.
end
resource_moved_temporarily (req: WSF_REQUEST) : BOOLEAN
-- Was `req.path_translated' moved temporarily?
require
req_attached: req /= Void
previously_existed: resource_previously_existed (req)
do
-- No. Override if this is not want you want.
end
end

View File

@@ -0,0 +1,98 @@
note
description: "[
Policy-driven handlers.
Implementers only need to concentrate on creating content.
]"
date: "$Date$"
revision: "$Revision$"
deferred class WSF_SKELETON_HANDLER
inherit
WSF_URI_TEMPLATE_ROUTING_HANDLER
redefine
execute
end
WSF_OPTIONS_POLICY
WSF_PREVIOUS_POLICY
WSF_METHOD_HELPER_FACTORY
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- <Precursor>
do
check
known_method: True -- Can't be done until WSF_METHOD_NOT_ALLOWED_RESPONSE
-- is refactored.
-- Then maybe this can become a precondition. But we will still (?)
-- need a check that it isn't CONNECT or TRACE (it MIGHT be HEAD).
end
if req.is_request_method ({HTTP_REQUEST_METHODS}.method_options) then
execute_options (req, res, router)
else
if attached new_method_helper (req.request_method) as l_helper then
execute_method (req, res, l_helper)
else
handle_internal_server_error (res)
end
end
end
execute_method (req: WSF_REQUEST; res: WSF_RESPONSE; a_helper: WSF_METHOD_HELPER)
-- Write response to `req' into `res', using `a_helper' as a logic helper.
require
req_attached: req /= Void
res_attached: res /= Void
a_helper_attached: a_helper /= Void
do
check_resource_exists (req, a_helper)
if a_helper.resource_exists then
a_helper.execute_existing_resource (req, res, Current)
else
if attached req.http_if_match as l_if_match and then l_if_match.same_string ("*") then
a_helper.handle_precondition_failed (req, res)
else
a_helper.execute_new_resource (req, res, Current)
end
end
end
check_resource_exists (req: WSF_REQUEST; a_helper: WSF_METHOD_HELPER)
-- Call `a_helper.set_resource_exists' to indicate that `req.path_translated'
-- is the name of an existing resource.
-- Optionally, also call `req.set_server_data', if this is now available as a by-product
-- of the existence check.
require
req_attached: req /= Void
a_helper_attached: a_helper /= Void
deferred
end
handle_internal_server_error (res: WSF_RESPONSE)
-- Write "Internal Server Error" response to `res'.
require
res_attached: res /= Void
local
h: HTTP_HEADER
m: STRING_8
do
create h.make
h.put_content_type_text_plain
m := "Server failed to handle request properly"
h.put_content_length (m.count)
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
res.put_string (m)
ensure
response_status_is_set: res.status_is_set
status_is_service_unavailable: res.status_code = {HTTP_STATUS_CODE}.internal_server_error
body_sent: res.message_committed and then res.transfered_content_length > 0
end
end