Merge changes from Javier

- update on RESTbuck examples
- new example
- fixed bad typo in WSF_REQUEST

Reverted some changes such as
- http_client_response: keep the headers as a list to handle multiple message-value with same message-name

Fixed simple and simple_file example
Improved HTTP_HEADER

Changed libcurl implementation for http client
- now the header from the context really overwrite any of the session headers
- better design which is more strict, and remove any doubt about context's header usage
This commit is contained in:
Jocelyn Fiat
2011-12-12 16:03:38 +01:00
38 changed files with 779 additions and 186 deletions

View File

@@ -0,0 +1,26 @@
note
description: "Summary description for {DATABASE_API}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
DATABASE_API
create
make
feature -- Initialization
make
do
create orders.make (10)
end
feature -- Access
orders: HASH_TABLE [ORDER, STRING]
;note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,19 @@
note
description: "Summary description for {SHARED_DATABASE_API}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SHARED_DATABASE_API
feature -- Access
db_access: DATABASE_API
once
create Result.make
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,90 @@
note
description: "Summary description for {ITEM}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
ITEM
inherit
ITEM_CONSTANTS
create
make
feature -- Initialization
make ( a_name : STRING_32 ; a_size:STRING_32; a_option: STRING_32; a_quantity:INTEGER_8)
do
set_name (a_name)
set_size (a_size)
set_option (a_option)
set_quantity (a_quantity)
end
feature -- Access
name : STRING
-- product name type of Coffee(Late, Cappuccino, Expresso)
option : STRING
-- customization option Milk (skim, semi, whole)
size : STRING
-- small, mediumm large
quantity :INTEGER
feature -- Element Change
set_name (a_name: STRING)
require
valid_name: is_valid_coffee_type (a_name)
do
name := a_name
ensure
name_assigned : name.same_string(a_name)
end
set_size (a_size: STRING)
require
valid_size : is_valid_size_option (a_size)
do
size := a_size
ensure
size_assigned : size.same_string(a_size)
end
set_option (an_option: STRING)
require
valid_option : is_valid_milk_type (an_option)
do
option := an_option
ensure
option_assigned : option.same_string (an_option)
end
set_quantity (a_quantity: INTEGER)
require
valid_quantity : a_quantity > 0
do
quantity := a_quantity
ensure
quantity_assigned : quantity = a_quantity
end
feature -- Report
hash_code: INTEGER
--Hash code value
do
Result := option.hash_code + name.hash_code + size.hash_code + quantity.hash_code
end
invariant
valid_size : is_valid_size_option (size)
valid_coffe : is_valid_coffee_type (name)
valid_customization : is_valid_milk_type (option)
valid_quantity : quantity > 0
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,54 @@
note
description: "Summary description for {ITEM_CONSTANTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
ITEM_CONSTANTS
feature -- Access
is_valid_coffee_type (a_type: STRING) : BOOLEAN
--is `a_type' a valid coffee type
do
a_type.to_lower
coffe_types.compare_objects
Result := coffe_types.has (a_type)
end
Coffe_types : ARRAY[STRING]
-- List of valid Coffee types
once
Result := <<"late","cappuccino", "expresso">>
end
is_valid_milk_type (a_type: STRING) : BOOLEAN
--is `a_type' a valid milk type
do
a_type.to_lower
milk_types.compare_objects
Result := milk_types.has (a_type)
end
Milk_types : ARRAY[STRING]
-- List of valid Milk types
once
Result := <<"skim","semi", "whole">>
end
is_valid_size_option (an_option: STRING) : BOOLEAN
--is `an_option' a valid size option
do
an_option.to_lower
size_options.compare_objects
Result := size_options.has (an_option)
end
Size_options : ARRAY[STRING]
-- List of valid Size_options
once
Result := <<"small","mediumn", "large">>
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,170 @@
note
description: "Summary description for {JSON_ORDER_CONVERTER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
JSON_ORDER_CONVERTER
inherit
JSON_CONVERTER
create
make
feature -- Initialization
make
do
create object.make ("","","")
end
feature -- Access
object : ORDER
value : detachable JSON_OBJECT
feature -- Conversion
from_json (j: attached like value): detachable like object
-- Convert from JSON value. Returns Void if unable to convert
local
s_id, s_location, s_status: detachable STRING_32
q: INTEGER_8
o: ORDER
i : ITEM
l_array : detachable ARRAYED_LIST [JSON_VALUE]
is_valid_from_json : BOOLEAN
do
is_valid_from_json := True
s_id ?= json.object (j.item (id_key), Void)
s_location ?= json.object (j.item (location_key), Void)
s_status ?= json.object (j.item (status_key), Void)
create o.make ("", s_location, s_status)
if attached {JSON_ARRAY} j.item (items_key) as l_val then
l_array := l_val.array_representation
from
l_array.start
until
l_array.after
loop
if attached {JSON_OBJECT} l_array.item_for_iteration as jv then
if attached {INTEGER_8} json.object (jv.item (quantity_key), Void) as l_integer then
q := l_integer
else
q := 0
end
if
attached {STRING_32} json.object (jv.item (name_key), Void) as s_name and then
attached {STRING_32} json.object (jv.item (size_key), Void) as s_key and then
attached {STRING_32} json.object (jv.item (option_key), Void) as s_option
then
if is_valid_item_customization (s_name, s_key, s_option,q) then
create i.make (s_name, s_key, s_option, q)
o.add_item (i)
else
is_valid_from_json := False
end
else
is_valid_from_json := False
end
end
l_array.forth
end
end
if not is_valid_from_json or o.items.is_empty then
Result := Void
else
Result := o
end
end
to_json (o: like object): like value
-- Convert to JSON value
local
ja : JSON_ARRAY
i : ITEM
jv: JSON_OBJECT
do
create Result.make
-- Result.put (json.value (o.id), id_key)
Result.put (json.value (o.location), location_key)
Result.put (json.value (o.status), status_key)
from
create ja.make_array
o.items.start
until
o.items.after
loop
i := o.items.item_for_iteration
create jv.make
jv.put (json.value (i.name), name_key)
jv.put (json.value (i.size),size_key)
jv.put (json.value (i.quantity), quantity_key)
jv.put (json.value (i.option), option_key)
ja.add (jv)
o.items.forth
end
Result.put (ja, items_key)
end
feature {NONE} -- Implementation
id_key: JSON_STRING
once
create Result.make_json ("id")
end
location_key: JSON_STRING
once
create Result.make_json ("location")
end
status_key: JSON_STRING
once
create Result.make_json ("status")
end
items_key : JSON_STRING
once
create Result.make_json ("items")
end
name_key : JSON_STRING
once
create Result.make_json ("name")
end
size_key : JSON_STRING
once
create Result.make_json ("size")
end
quantity_key : JSON_STRING
once
create Result.make_json ("quantity")
end
option_key : JSON_STRING
once
create Result.make_json ("option")
end
feature -- Validation
is_valid_item_customization ( name : STRING_32; size: STRING_32; option : STRING_32; quantity : INTEGER_8 ) : BOOLEAN
local
ic : ITEM_CONSTANTS
do
create ic
Result := ic.is_valid_coffee_type (name) and ic.is_valid_milk_type (option) and ic.is_valid_size_option (size) and quantity > 0
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,114 @@
note
description: "Summary description for {ORDER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
ORDER
create
make
feature -- Initialization
make ( an_id : detachable STRING_32; a_location: detachable STRING_32; a_status: detachable STRING_32)
do
create {ARRAYED_LIST [ITEM]} items.make (10)
if an_id /= Void then
set_id (an_id)
else
set_id ("")
end
if a_location /= Void then
set_location (a_location)
else
set_location ("")
end
if a_status /= Void then
set_status (a_status)
else
set_status ("")
end
revision := 0
end
feature -- Access
id : STRING_32
location : STRING_32
items: LIST[ITEM]
status : STRING_32
revision : INTEGER
feature -- element change
set_id (an_id : STRING_32)
do
id := an_id
ensure
id_assigned : id.same_string (an_id)
end
set_location (a_location : STRING_32)
do
location := a_location
ensure
location_assigned : location.same_string (a_location)
end
set_status (a_status : STRING_32)
do
status := a_status
ensure
status_asigned : status.same_string (a_status)
end
add_item (a_item : ITEM)
require
valid_item: a_item /= Void
do
items.force (a_item)
ensure
has_item : items.has (a_item)
end
add_revision
do
revision := revision + 1
ensure
revision_incremented : old revision + 1 = revision
end
feature -- Etag
etag : STRING_32
-- Etag generation for Order objects
do
Result := hash_code.out + revision.out
end
feature -- Output
feature -- Report
hash_code: INTEGER_32
-- Hash code value
do
from
items.start
Result := items.item.hash_code
until
items.off
loop
Result:= ((Result \\ 8388593) |<< 8) + items.item.hash_code
items.forth
end
if items.count > 1 then
Result := Result \\ items.count
end
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,56 @@
note
description: "Summary description for {ORDER_TRANSITIONS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
ORDER_VALIDATION
feature -- Access
is_valid_status_state (a_status: STRING) : BOOLEAN
--is `a_status' a valid coffee order state
do
a_status.to_lower
Order_states.compare_objects
Result := Order_states.has (a_status)
end
Order_states : ARRAY[STRING]
-- List of valid status states
once
Result := <<"submitted","pay","payed", "cancel","canceled","prepare","prepared","deliver","completed">>
end
is_valid_transition (order:ORDER a_status : STRING) :BOOLEAN
-- Given the current order state, determine if the transition is valid
do
a_status.to_lower
if order.status.same_string ("submitted") then
Result := a_status.same_string ("pay") or a_status.same_string ("cancel") or order.status.same_string (a_status)
elseif order.status.same_string ("pay") then
Result := a_status.same_string ("payed") or order.status.same_string (a_status)
elseif order.status.same_string ("cancel") then
Result := a_status.same_string ("canceled") or order.status.same_string (a_status)
elseif order.status.same_string ("payed") then
Result := a_status.same_string ("prepared") or order.status.same_string (a_status)
elseif order.status.same_string ("prepared") then
Result := a_status.same_string ("deliver") or order.status.same_string (a_status)
elseif order.status.same_string ("deliver") then
Result := a_status.same_string ("completed") or order.status.same_string (a_status)
end
end
is_state_valid_to_update ( a_status : STRING) : BOOLEAN
-- Given the current state `a_status' of an order, is possible to update the order?
do
if a_status.same_string ("submitted") or else a_status.same_string ("pay") or else a_status.same_string ("payed") then
Result := true
end
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,19 @@
note
description: "Summary description for {SHARED_ORDER_VALIDATION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
SHARED_ORDER_VALIDATION
feature
order_validation : ORDER_VALIDATION
once
create Result
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,363 @@
note
description: "{ORDER_HANDLER} handle the resources that we want to expose"
author: ""
date: "$Date$"
revision: "$Revision$"
class
ORDER_HANDLER [C -> REQUEST_HANDLER_CONTEXT]
inherit
REQUEST_HANDLER [C]
REQUEST_RESOURCE_HANDLER_HELPER [C]
redefine
do_get,
do_post,
do_put,
do_delete
end
SHARED_DATABASE_API
SHARED_EJSON
REFACTORING_HELPER
SHARED_ORDER_VALIDATION
feature -- execute
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute request handler
do
execute_methods (ctx, req, res)
end
feature -- API DOC
api_doc : STRING = "URI:/order METHOD: POST%N URI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
feature -- HTTP Methods
do_get (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Using GET to retrieve resource information.
-- If the GET request is SUCCESS, we response with
-- 200 OK, and a representation of the order
-- If the GET request is not SUCCESS, we response with
-- 404 Resource not found
-- If is a Condition GET and the resource does not change we send a
-- 304, Resource not modifed
local
id : STRING
do
if attached req.orig_path_info as orig_path then
id := get_order_id_from_path (orig_path)
if attached retrieve_order (id) as l_order then
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
handle_resource_not_found_response ("The following resource" + orig_path + " is not found ", ctx, req, res)
end
end
end
is_conditional_get (req : WSF_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_string_variable ("HTTP_IF_NONE_MATCH") as if_none_match then
create etag_util
if if_none_match.same_string (etag_util.md5_digest (l_order.out).as_string_32) then
Result := True
end
end
end
compute_response_get (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
local
h: HTTP_HEADER
l_msg : STRING
etag_utils : ETAG_UTILS
do
create h.make
create etag_utils
h.put_status ({HTTP_STATUS_CODE}.ok)
h.put_content_type_application_json
if attached {JSON_VALUE} json.value (l_order) as jv then
l_msg := jv.representation
h.put_content_length (l_msg.count)
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")
end
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
res.set_status_code ({HTTP_STATUS_CODE}.ok)
res.write_header_text (h.string)
res.write_string (l_msg)
end
end
do_put (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Updating a resource with PUT
-- A successful PUT request will not create a new resource, instead it will
-- change the state of the resource identified by the current uri.
-- If success we response with 200 and the updated order.
-- 404 if the order is not found
-- 400 in case of a bad request
-- 500 internal server error
-- If the request is a Conditional PUT, and it does not mat we response
-- 415, precondition failed.
local
l_put: STRING
l_order : detachable ORDER
id : STRING
do
if attached req.orig_path_info as orig_path then
id := get_order_id_from_path (orig_path)
req.input.read_string (req.content_length_value.as_integer_32)
l_put := req.input.last_string
l_order := extract_order_request(l_put)
if l_order /= Void and then db_access.orders.has_key (id) then
l_order.set_id (id)
if is_valid_to_update(l_order) then
if is_conditional_put (req, l_order) then
update_order( l_order)
compute_response_put (ctx, req, res, l_order)
else
handle_precondition_fail_response ("", ctx, req, res)
end
else
--| FIXME: Here we need to define the Allow methods
handle_resource_conflict_response (l_put +"%N There is conflict while trying to update the order, the order could not be update in the current state", ctx, req, res)
end
else
handle_bad_request_response (l_put +"%N is not a valid ORDER, maybe the order does not exist in the system", ctx, req, res)
end
end
end
is_conditional_put (req : WSF_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_string_variable ("HTTP_IF_MATCH") as if_match then
create etag_util
if if_match.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: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
local
h: HTTP_HEADER
joc : JSON_ORDER_CONVERTER
etag_utils : ETAG_UTILS
do
create h.make
create joc.make
create etag_utils
json.add_converter(joc)
create h.make
h.put_status ({HTTP_STATUS_CODE}.ok)
h.put_content_type_application_json
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")
end
h.add_header ("etag:" + etag_utils.md5_digest (l_order.out))
if attached {JSON_VALUE} json.value (l_order) as jv then
h.put_content_length (jv.representation.count)
res.set_status_code ({HTTP_STATUS_CODE}.ok)
res.write_header_text (h.string)
res.write_string (jv.representation)
end
end
do_delete (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Here we use DELETE to cancel an order, if that order is in state where
-- it can still be canceled.
-- 200 if is ok
-- 404 Resource not found
-- 405 if consumer and service's view of the resouce state is inconsisent
-- 500 if we have an internal server error
local
id: STRING
do
if attached req.orig_path_info as orig_path then
id := get_order_id_from_path (orig_path)
if db_access.orders.has_key (id) then
if is_valid_to_delete (id) then
delete_order( id)
compute_response_delete (ctx, req, res)
else
--| FIXME: Here we need to define the Allow methods
handle_method_not_allowed_response (orig_path + "%N There is conflict while trying to delete the order, the order could not be deleted in the current state", ctx, req, res)
end
else
handle_resource_not_found_response (orig_path + " not found in this server", ctx, req, res)
end
end
end
compute_response_delete (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
local
h : HTTP_HEADER
do
create h.make
h.put_status ({HTTP_STATUS_CODE}.no_content)
h.put_content_type_application_json
if attached req.request_time as time then
h.put_utc_date (time)
end
res.set_status_code ({HTTP_STATUS_CODE}.no_content)
res.write_header_text (h.string)
end
do_post (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Here the convention is the following.
-- POST is used for creation and the server determines the URI
-- of the created resource.
-- If the request post is SUCCESS, the server will create the order and will response with
-- HTTP_RESPONSE 201 CREATED, the Location header will contains the newly created order's URI
-- if the request post is not SUCCESS, the server will response with
-- HTTP_RESPONSE 400 BAD REQUEST, the client send a bad request
-- HTTP_RESPONSE 500 INTERNAL_SERVER_ERROR, when the server can deliver the request
local
l_post: STRING
do
req.input.read_string (req.content_length_value.as_integer_32)
l_post := req.input.last_string
if attached extract_order_request (l_post) as l_order then
save_order (l_order)
compute_response_post (ctx, req, res, l_order)
else
handle_bad_request_response (l_post +"%N is not a valid ORDER", ctx, req, res)
end
end
compute_response_post (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE; l_order : ORDER)
local
h: HTTP_HEADER
l_msg : STRING
l_location : STRING
joc : JSON_ORDER_CONVERTER
do
create h.make
create joc.make
json.add_converter(joc)
h.put_status ({HTTP_STATUS_CODE}.created)
h.put_content_type_application_json
if attached {JSON_VALUE} json.value (l_order) as jv then
l_msg := jv.representation
h.put_content_length (l_msg.count)
if attached req.http_host as host then
l_location := "http://" + host + req.request_uri + "/" + l_order.id
h.put_location (l_location)
end
if attached req.request_time as time then
h.put_utc_date (time)
end
res.set_status_code ({HTTP_STATUS_CODE}.created)
res.write_header_text (h.string)
res.write_string (l_msg)
end
end
feature {NONE} -- URI helper methods
get_order_id_from_path (a_path: READABLE_STRING_32) : STRING
do
Result := a_path.split ('/').at (3)
end
feature {NONE} -- Implementation Repository Layer
retrieve_order ( id : STRING) : detachable ORDER
-- get the order by id if it exist, in other case, Void
do
Result := db_access.orders.item (id)
end
save_order (an_order: ORDER)
-- save the order to the repository
local
i : INTEGER
do
from
i := 1
until
not db_access.orders.has_key ((db_access.orders.count + i).out)
loop
i := i + 1
end
an_order.set_id ((db_access.orders.count + i).out)
an_order.set_status ("submitted")
an_order.add_revision
db_access.orders.force (an_order, an_order.id)
end
is_valid_to_delete ( an_id : STRING) : BOOLEAN
-- Is the order identified by `an_id' in a state whre it can still be deleted?
do
if attached retrieve_order (an_id) as l_order then
if order_validation.is_state_valid_to_update (l_order.status) then
Result := True
end
end
end
is_valid_to_update (an_order: ORDER) : BOOLEAN
-- Check if there is a conflict while trying to update the order
do
if attached retrieve_order (an_order.id) as l_order then
if order_validation.is_state_valid_to_update (l_order.status) and then order_validation.is_valid_status_state (an_order.status) and then
order_validation.is_valid_transition (l_order, an_order.status) then
Result := True
end
end
end
update_order (an_order: ORDER)
-- update the order to the repository
do
an_order.add_revision
db_access.orders.force (an_order, an_order.id)
end
delete_order (an_order: STRING)
-- update the order to the repository
do
db_access.orders.remove (an_order)
end
extract_order_request (l_post : STRING) : detachable ORDER
-- extract an object Order from the request, or Void
-- if the request is invalid
local
parser : JSON_PARSER
joc : JSON_ORDER_CONVERTER
do
create joc.make
json.add_converter(joc)
create parser.make_parser (l_post)
if attached parser.parse as jv and parser.is_parsed then
Result ?= json.object (jv, "ORDER")
end
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -0,0 +1,80 @@
note
description : "Objects that ..."
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
class
RESTBUCKS_SERVER
inherit
ANY
URI_TEMPLATE_ROUTED_SERVICE
ROUTED_SERVICE_HELPER
create
make
feature {NONE} -- Initialization
make
local
s: DEFAULT_SERVICE
do
initialize_router
create s.make_and_launch (agent execute)
end
create_router
do
create router.make (2)
end
setup_router
local
order_handler: ORDER_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
do
create order_handler
router.map_with_request_methods ("/order", order_handler, <<"POST">>)
router.map_with_request_methods ("/order/{orderid}", order_handler, <<"GET", "DELETE", "PUT">>)
end
feature -- Execution
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
-- I'm using this method to handle the method not allowed response
-- in the case that the given uri does not have a corresponding http method
-- to handle it.
local
h : HTTP_HEADER
l_description : STRING
l_api_doc : STRING
do
if req.content_length_value > 0 then
req.input.read_string (req.content_length_value.as_integer_32)
end
create h.make
h.put_status ({HTTP_STATUS_CODE}.method_not_allowed)
h.put_content_type_text_plain
l_api_doc := "%NPlease check the API%NURI:/order METHOD: POST%NURI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc
h.put_content_length (l_description.count)
h.put_current_date
res.set_status_code ({HTTP_STATUS_CODE}.method_not_allowed)
res.write_header_text (h.string)
res.write_string (l_description)
end
note
copyright: "2011-2011, Javier Velilla 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

View File

@@ -0,0 +1,33 @@
note
description: "Summary description for {ETAG_UTILS}."
date: "$Date$"
revision: "$Revision$"
class
ETAG_UTILS
inherit
ARRAY_FACILITIES
feature -- Access
md5_digest (a_string: STRING): STRING
-- Cryptographic hash function that produces a 128-bit (16-byte) hash value, based on `a_string'
local
md5: MD5
output: SPECIAL [NATURAL_8]
do
create md5.make
create output.make_filled (0, 16)
md5.sink_string (a_string)
md5.do_final (output, 0)
Result := as_natural_32_be (output, 0).to_hex_string
Result.append (as_natural_32_be (output, 4).to_hex_string)
Result.append (as_natural_32_be (output, 8).to_hex_string)
Result.append (as_natural_32_be (output, 12).to_hex_string)
end
note
copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end