Update Restbucks example: Conditional GET, PUT.
Added a response method to support resource not modified. Added a ETAG_UTILS class to calcule md5_digest. Added ext libs eel and eapml.
This commit is contained in:
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -10,3 +10,9 @@
|
|||||||
[submodule "ext/ise_library/curl"]
|
[submodule "ext/ise_library/curl"]
|
||||||
path = ext/ise_library/curl
|
path = ext/ise_library/curl
|
||||||
url = http://github.com/EiffelSoftware/mirror-Eiffel-cURL.git
|
url = http://github.com/EiffelSoftware/mirror-Eiffel-cURL.git
|
||||||
|
[submodule "ext/crypto/eel"]
|
||||||
|
path = ext/crypto/eel
|
||||||
|
url = http://github.com/Eiffel-World/eel.git
|
||||||
|
[submodule "ext/crypto/eapml"]
|
||||||
|
path = ext/crypto/eapml
|
||||||
|
url = http://github.com/Eiffel-World/eapml.git
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
<library name="default_nino" location="..\..\library\server\ewsgi\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||||
<library name="json" location="..\..\ext\text\json\library\json-safe.ecf" readonly="false"/>
|
|
||||||
<library name="http" location="..\..\library\protocol\http\http-safe.ecf" readonly="false"/>
|
<library name="http" location="..\..\library\protocol\http\http-safe.ecf" readonly="false"/>
|
||||||
|
<library name="json" location="..\..\ext\text\json\library\json-safe.ecf" readonly="false"/>
|
||||||
|
<library name="eel" location="..\..\ext\crypto\eel\eel-safe.ecf" readonly="false"/>
|
||||||
<library name="router" location="..\..\library\server\request\router\router-safe.ecf" readonly="false"/>
|
<library name="router" location="..\..\library\server\request\router\router-safe.ecf" readonly="false"/>
|
||||||
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
|
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||||
<cluster name="src" location="src\" recursive="true"/>
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ feature -- Etag
|
|||||||
Result := hash_code.out + revision.out
|
Result := hash_code.out + revision.out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature -- Output
|
||||||
|
|
||||||
feature -- Report
|
feature -- Report
|
||||||
|
|
||||||
hash_code: INTEGER_32
|
hash_code: INTEGER_32
|
||||||
|
|||||||
@@ -40,25 +40,48 @@ feature -- HTTP Methods
|
|||||||
-- 200 OK, and a representation of the order
|
-- 200 OK, and a representation of the order
|
||||||
-- If the GET request is not SUCCESS, we response with
|
-- If the GET request is not SUCCESS, we response with
|
||||||
-- 404 Resource not found
|
-- 404 Resource not found
|
||||||
|
-- If is a Condition GET and the resource does not change we send a
|
||||||
|
-- 304, Resource not modifed
|
||||||
local
|
local
|
||||||
id : STRING
|
id : STRING
|
||||||
do
|
do
|
||||||
if attached req.orig_path_info as orig_path then
|
if attached req.orig_path_info as orig_path then
|
||||||
id := get_order_id_from_path (orig_path)
|
id := get_order_id_from_path (orig_path)
|
||||||
if attached retrieve_order (id) as l_order then
|
if attached retrieve_order (id) as l_order then
|
||||||
compute_response_get (ctx, req, res, l_order)
|
if is_conditional_get (req, l_order) then
|
||||||
|
handle_resource_not_modified_response ("The resource" + orig_path + "does not change", ctx, req, res)
|
||||||
|
else
|
||||||
|
compute_response_get (ctx, req, res, l_order)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
handle_resource_not_found_response ("The following resource" + orig_path + " is not found ", ctx, req, res)
|
handle_resource_not_found_response ("The following resource" + orig_path + " is not found ", ctx, req, res)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_conditional_get (req : WGI_REQUEST; l_order : ORDER) : BOOLEAN
|
||||||
|
-- Check if If-None-Match is present and then if there is a representation that has that etag
|
||||||
|
-- if the representation hasn't changed, we return TRUE
|
||||||
|
-- then the response is a 304 with no entity body returned.
|
||||||
|
local
|
||||||
|
etag_util : ETAG_UTILS
|
||||||
|
do
|
||||||
|
if attached req.meta_variable ("HTTP_IF_NONE_MATCH") as if_none_match then
|
||||||
|
create etag_util
|
||||||
|
if if_none_match.as_string.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
compute_response_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
compute_response_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
||||||
local
|
local
|
||||||
h: EWF_HEADER
|
h: EWF_HEADER
|
||||||
l_msg : STRING
|
l_msg : STRING
|
||||||
|
etag_utils : ETAG_UTILS
|
||||||
do
|
do
|
||||||
create h.make
|
create h.make
|
||||||
|
create etag_utils
|
||||||
h.put_status ({HTTP_STATUS_CODE}.ok)
|
h.put_status ({HTTP_STATUS_CODE}.ok)
|
||||||
h.put_content_type_application_json
|
h.put_content_type_application_json
|
||||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||||
@@ -67,6 +90,7 @@ feature -- HTTP Methods
|
|||||||
if attached req.request_time as time then
|
if attached req.request_time as time then
|
||||||
h.add_header ("Date:" + time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
h.add_header ("Date:" + time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
||||||
end
|
end
|
||||||
|
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
|
||||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
res.write_headers_string (h.string)
|
res.write_headers_string (h.string)
|
||||||
res.write_string (l_msg)
|
res.write_string (l_msg)
|
||||||
@@ -81,6 +105,8 @@ feature -- HTTP Methods
|
|||||||
-- 404 if the order is not found
|
-- 404 if the order is not found
|
||||||
-- 400 in case of a bad request
|
-- 400 in case of a bad request
|
||||||
-- 500 internal server error
|
-- 500 internal server error
|
||||||
|
-- If the request is a Conditional PUT, and it does not mat we response
|
||||||
|
-- 415, precondition failed.
|
||||||
local
|
local
|
||||||
l_post: STRING
|
l_post: STRING
|
||||||
l_order : detachable ORDER
|
l_order : detachable ORDER
|
||||||
@@ -90,8 +116,12 @@ feature -- HTTP Methods
|
|||||||
l_order := extract_order_request(l_post)
|
l_order := extract_order_request(l_post)
|
||||||
if l_order /= Void and then db_access.orders.has_key (l_order.id) then
|
if l_order /= Void and then db_access.orders.has_key (l_order.id) then
|
||||||
if is_valid_to_update(l_order) then
|
if is_valid_to_update(l_order) then
|
||||||
update_order( l_order)
|
if is_conditional_put (req, l_order) then
|
||||||
compute_response_put (ctx, req, res, l_order)
|
update_order( l_order)
|
||||||
|
compute_response_put (ctx, req, res, l_order)
|
||||||
|
else
|
||||||
|
handle_precondition_fail_response ("", ctx, req, res)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
--| FIXME: Here we need to define the Allow methods
|
--| FIXME: Here we need to define the Allow methods
|
||||||
handle_resource_conflict_response (l_post +"%N There is conflict while trying to update the order, the order could not be update in the current state", ctx, req, res)
|
handle_resource_conflict_response (l_post +"%N There is conflict while trying to update the order, the order could not be update in the current state", ctx, req, res)
|
||||||
@@ -101,13 +131,34 @@ feature -- HTTP Methods
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_conditional_put (req : WGI_REQUEST; order : ORDER) : BOOLEAN
|
||||||
|
-- Check if If-Match is present and then if there is a representation that has that etag
|
||||||
|
-- if the representation hasn't changed, we return TRUE
|
||||||
|
local
|
||||||
|
etag_util : ETAG_UTILS
|
||||||
|
do
|
||||||
|
if attached retrieve_order (order.id) as l_order then
|
||||||
|
if attached req.meta_variable ("HTTP_IF_MATCH") as if_match then
|
||||||
|
create etag_util
|
||||||
|
if if_match.as_string.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
compute_response_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
compute_response_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER)
|
||||||
local
|
local
|
||||||
h: EWF_HEADER
|
h: EWF_HEADER
|
||||||
joc : JSON_ORDER_CONVERTER
|
joc : JSON_ORDER_CONVERTER
|
||||||
|
etag_utils : ETAG_UTILS
|
||||||
do
|
do
|
||||||
create h.make
|
create h.make
|
||||||
create joc.make
|
create joc.make
|
||||||
|
create etag_utils
|
||||||
json.add_converter(joc)
|
json.add_converter(joc)
|
||||||
|
|
||||||
create h.make
|
create h.make
|
||||||
@@ -116,6 +167,7 @@ feature -- HTTP Methods
|
|||||||
if attached req.request_time as time then
|
if attached req.request_time as time then
|
||||||
h.add_header ("Date:" +time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
h.add_header ("Date:" +time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
|
||||||
end
|
end
|
||||||
|
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
|
||||||
if attached {JSON_VALUE} json.value (l_order) as jv then
|
if attached {JSON_VALUE} json.value (l_order) as jv then
|
||||||
h.put_content_length (jv.representation.count)
|
h.put_content_length (jv.representation.count)
|
||||||
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
res.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
@@ -133,7 +185,6 @@ feature -- HTTP Methods
|
|||||||
-- 500 if we have an internal server error
|
-- 500 if we have an internal server error
|
||||||
local
|
local
|
||||||
id: STRING
|
id: STRING
|
||||||
h : EWF_HEADER
|
|
||||||
do
|
do
|
||||||
if attached req.orig_path_info as orig_path then
|
if attached req.orig_path_info as orig_path then
|
||||||
id := get_order_id_from_path (orig_path)
|
id := get_order_id_from_path (orig_path)
|
||||||
|
|||||||
@@ -182,6 +182,25 @@ feature -- Handle responses
|
|||||||
res.write_string (a_description)
|
res.write_string (a_description)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handle_precondition_fail_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER )
|
||||||
|
local
|
||||||
|
h : EWF_HEADER
|
||||||
|
do
|
||||||
|
create h.make
|
||||||
|
h.put_status ({HTTP_STATUS_CODE}.precondition_failed)
|
||||||
|
if attached ctx.request_content_type (supported_content_types) as l_content_type then
|
||||||
|
h.put_content_type (l_content_type)
|
||||||
|
else
|
||||||
|
h.put_content_type ("*/*")
|
||||||
|
end
|
||||||
|
h.put_content_length (a_description.count)
|
||||||
|
h.put_current_date
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.precondition_failed)
|
||||||
|
res.write_headers_string (h.string)
|
||||||
|
res.write_string (a_description)
|
||||||
|
end
|
||||||
|
|
||||||
handle_internal_server_error (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER )
|
handle_internal_server_error (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER )
|
||||||
local
|
local
|
||||||
h : EWF_HEADER
|
h : EWF_HEADER
|
||||||
@@ -239,6 +258,26 @@ feature -- Handle responses
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
handle_resource_not_modified_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
h : EWF_HEADER
|
||||||
|
do
|
||||||
|
res.flush
|
||||||
|
create h.make
|
||||||
|
h.put_status ({HTTP_STATUS_CODE}.not_modified)
|
||||||
|
if attached ctx.request_content_type (supported_content_types) as l_content_type then
|
||||||
|
h.put_content_type (l_content_type)
|
||||||
|
else
|
||||||
|
h.put_content_type ("*/*")
|
||||||
|
end
|
||||||
|
h.put_content_length (a_description.count)
|
||||||
|
h.put_current_date
|
||||||
|
res.set_status_code ({HTTP_STATUS_CODE}.not_modified)
|
||||||
|
res.write_headers_string (h.string)
|
||||||
|
res.write_string (a_description)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
handle_resource_conflict_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
handle_resource_conflict_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
local
|
local
|
||||||
h : EWF_HEADER
|
h : EWF_HEADER
|
||||||
|
|||||||
Reference in New Issue
Block a user