diff --git a/examples/restbucks/client/client-safe.ecf b/examples/restbucks/client/client-safe.ecf index 183f9a01..39cf3bb9 100644 --- a/examples/restbucks/client/client-safe.ecf +++ b/examples/restbucks/client/client-safe.ecf @@ -12,6 +12,7 @@ + diff --git a/examples/restbucks/client/client.ecf b/examples/restbucks/client/client.ecf index 9e91c9dd..b9d0f22f 100644 --- a/examples/restbucks/client/client.ecf +++ b/examples/restbucks/client/client.ecf @@ -11,6 +11,7 @@ + diff --git a/examples/restbucks/client/src/restbuck_client.e b/examples/restbucks/client/src/restbuck_client.e index d340cb08..dec021d0 100644 --- a/examples/restbucks/client/src/restbuck_client.e +++ b/examples/restbucks/client/src/restbuck_client.e @@ -18,6 +18,8 @@ feature {NONE} -- Initialization h: LIBCURL_HTTP_CLIENT sess: HTTP_CLIENT_SESSION s: READABLE_STRING_8 + j: JSON_PARSER + id: detachable STRING do create h.make sess := h.new_session ("http://127.0.0.1") @@ -36,11 +38,23 @@ feature {NONE} -- Initialization ]" if attached sess.post ("/order", Void, s) as r then - print (r.body) + if attached r.body as m then + create j.make_parser (m) + + if j.is_parsed and attached j.parse_object as j_o then + if attached {JSON_STRING} j_o.item ("id") as l_id then + id := l_id.item + end + print (m) + io.put_new_line + + end + end end - if attached sess.get ("/order/1", Void) as r then + if id /= Void and then attached sess.get ("/order/" + id, Void) as r then print (r.body) + io.put_new_line end end diff --git a/examples/restbucks/license.lic b/examples/restbucks/license.lic new file mode 100644 index 00000000..6928e20b --- /dev/null +++ b/examples/restbucks/license.lic @@ -0,0 +1,4 @@ +${NOTE_KEYWORD} + copyright: "2011-${YEAR}, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + diff --git a/examples/restbucks/src/database/database_api.e b/examples/restbucks/src/database/database_api.e index 1ebeaffa..239b7fb1 100644 --- a/examples/restbucks/src/database/database_api.e +++ b/examples/restbucks/src/database/database_api.e @@ -9,13 +9,18 @@ class create make -feature --Initialization +feature -- Initialization + make do create orders.make (10) end feature -- Access - orders : HASH_TABLE[ORDER,STRING] + 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 diff --git a/examples/restbucks/src/database/shared_database_api.e b/examples/restbucks/src/database/shared_database_api.e index 0a27b7cd..6d99c4ed 100644 --- a/examples/restbucks/src/database/shared_database_api.e +++ b/examples/restbucks/src/database/shared_database_api.e @@ -6,9 +6,14 @@ note class SHARED_DATABASE_API -feature + +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 diff --git a/examples/restbucks/src/domain/item.e b/examples/restbucks/src/domain/item.e index 8d5c28d6..115c3c8a 100644 --- a/examples/restbucks/src/domain/item.e +++ b/examples/restbucks/src/domain/item.e @@ -84,4 +84,7 @@ invariant 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 diff --git a/examples/restbucks/src/domain/item_constants.e b/examples/restbucks/src/domain/item_constants.e index 07dfc0d0..2894894e 100644 --- a/examples/restbucks/src/domain/item_constants.e +++ b/examples/restbucks/src/domain/item_constants.e @@ -48,4 +48,7 @@ feature -- Access 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 diff --git a/examples/restbucks/src/domain/json_order_converter.e b/examples/restbucks/src/domain/json_order_converter.e index 48dcafbe..6b6d7e1d 100644 --- a/examples/restbucks/src/domain/json_order_converter.e +++ b/examples/restbucks/src/domain/json_order_converter.e @@ -6,64 +6,73 @@ class JSON_ORDER_CONVERTER + inherit JSON_CONVERTER + create make + feature -- Initialization + make do - create object.make ("","","") + create object.make ("", "", "") end + feature -- Access - object : ORDER + object: ORDER + + value: detachable JSON_OBJECT - value : detachable JSON_OBJECT feature -- Conversion - from_json (j: attached like value): detachable like object + from_json (j: attached like value): detachable like object -- Convert from JSON value. Returns Void if unable to convert local - lstr1, lstr2, lstr3 : detachable STRING_32 - q: detachable INTEGER_8 + s_name, s_key, s_option: detachable STRING_32 + q: INTEGER_8 o: ORDER i : ITEM - l_val : detachable JSON_ARRAY - l_array : detachable ARRAYED_LIST[JSON_VALUE] - jv : detachable JSON_OBJECT + l_array : detachable LIST [JSON_VALUE] is_valid_from_json : BOOLEAN do is_valid_from_json := True - lstr1 ?= json.object (j.item (id_key), Void) - lstr2 ?= json.object (j.item (location_key), Void) - lstr3 ?= json.object (j.item (status_key), Void) - l_val ?= j.item (items_key) - create o.make (lstr1, lstr2, lstr3) + s_name ?= json.object (j.item (id_key), Void) + s_key ?= json.object (j.item (location_key), Void) + s_option ?= json.object (j.item (status_key), Void) - if l_val /= void then + create o.make (s_name, s_key, s_option) + + 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 - jv ?= l_array.item_for_iteration - if jv /= Void then - lstr1 ?= json.object (jv.item (name_key), Void) - lstr2 ?= json.object (jv.item (size_key), Void) - lstr3 ?= json.object (jv.item (option_key), Void) - q ?= json.object (jv.item (quantity_key),Void) - if lstr1/= Void and then lstr2 /= Void and then lstr3 /= Void then - if is_valid_item_customization(lstr1,lstr2,lstr3,q) then - create i.make (lstr1, lstr2,lstr3, q) + 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 + + s_name ?= json.object (jv.item (id_key), Void) + s_key ?= json.object (jv.item (location_key), Void) + s_option ?= json.object (jv.item (status_key), Void) + + if s_name /= Void and s_key /= Void and s_option /= Void 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 + is_valid_from_json := False end else - is_valid_from_json := false + is_valid_from_json := False end end @@ -75,7 +84,6 @@ feature -- Conversion else Result := o end - end to_json (o: like object): like value @@ -98,7 +106,7 @@ feature -- Conversion 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.size), size_key) jv.put (json.value (i.quantity), quantity_key) jv.put (json.value (i.option), option_key) ja.add (jv) @@ -108,6 +116,7 @@ feature -- Conversion end feature {NONE} -- Implementation + id_key: JSON_STRING once create Result.make_json ("id") @@ -147,12 +156,12 @@ feature -- Conversion 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 @@ -163,4 +172,7 @@ feature -- Validation 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 diff --git a/examples/restbucks/src/domain/order.e b/examples/restbucks/src/domain/order.e index 13a8b54d..d7092a5f 100644 --- a/examples/restbucks/src/domain/order.e +++ b/examples/restbucks/src/domain/order.e @@ -12,14 +12,14 @@ 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) + create {ARRAYED_LIST [ITEM]} items.make (10) if an_id /= Void then - set_id(an_id) + set_id (an_id) else set_id ("") end if a_location /= Void then - set_location(a_location) + set_location (a_location) else set_location ("") end @@ -40,6 +40,7 @@ feature -- Access revision : INTEGER feature -- element change + set_id (an_id : STRING_32) do id := an_id @@ -61,7 +62,6 @@ feature -- element change status_asigned : status.same_string (a_status) end - add_item (a_item : ITEM) require valid_item: a_item /= Void @@ -71,7 +71,6 @@ feature -- element change has_item : items.has (a_item) end - add_revision do revision := revision + 1 @@ -82,7 +81,7 @@ feature -- element change feature -- Etag etag : STRING_32 - -- Etag generation for Order objects + -- Etag generation for Order objects do Result := hash_code.out + revision.out end @@ -106,4 +105,7 @@ feature -- Report end end +note + copyright: "2011-2011, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/examples/restbucks/src/domain/order_validation.e b/examples/restbucks/src/domain/order_validation.e index a4cc18e5..d4bd39b9 100644 --- a/examples/restbucks/src/domain/order_validation.e +++ b/examples/restbucks/src/domain/order_validation.e @@ -51,4 +51,7 @@ feature -- Access end +note + copyright: "2011-2011, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" end diff --git a/examples/restbucks/src/domain/shared_order_validation.e b/examples/restbucks/src/domain/shared_order_validation.e index 90d09ec7..37958ff4 100644 --- a/examples/restbucks/src/domain/shared_order_validation.e +++ b/examples/restbucks/src/domain/shared_order_validation.e @@ -13,4 +13,7 @@ feature 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 diff --git a/examples/restbucks/src/resource/order_handler.e b/examples/restbucks/src/resource/order_handler.e index 46382ffb..b53b38e8 100644 --- a/examples/restbucks/src/resource/order_handler.e +++ b/examples/restbucks/src/resource/order_handler.e @@ -5,10 +5,10 @@ note revision: "$Revision$" class - ORDER_HANDLER[C -> REQUEST_HANDLER_CONTEXT] + ORDER_HANDLER [C -> REQUEST_HANDLER_CONTEXT] inherit - REQUEST_HANDLER[C] - REQUEST_RESOURCE_HANDLER_HELPER[C] + REQUEST_HANDLER [C] + REQUEST_RESOURCE_HANDLER_HELPER [C] redefine do_get, do_post, @@ -20,8 +20,8 @@ inherit REFACTORING_HELPER SHARED_ORDER_VALIDATION - feature -- execute + execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute request handler do @@ -29,49 +29,51 @@ feature -- execute 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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - -- 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 + -- 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 local joc : JSON_ORDER_CONVERTER l_order : detachable ORDER jv : detachable JSON_VALUE id : STRING - uri : LIST[READABLE_STRING_32] + uri : LIST [READABLE_STRING_32] h : EWF_HEADER do - if attached req.orig_path_info as orig_path then - uri := orig_path.split ('/') - id := uri.at (3) - create joc.make - json.add_converter(joc) - if db_access.orders.has_key (id) then - l_order := db_access.orders.item (id) - jv ?= json.value (l_order) - if attached jv as j then - create h.make - h.put_status (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 - if l_order /= Void then - h.add_header ("Etag: " + l_order.etag) - end - res.set_status_code (ok) - res.write_headers_string (h.string) - res.write_string (j.representation) + if attached req.orig_path_info as orig_path then + uri := orig_path.split ('/') + id := uri.at (3) + create joc.make + json.add_converter(joc) + if db_access.orders.has_key (id) then + l_order := db_access.orders.item (id) + jv ?= json.value (l_order) + if attached jv as j then + 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 - else - handle_resource_not_found_response ("The following resource"+ orig_path+ " is not found ", req.content_type, res) + if l_order /= Void then + h.add_header ("Etag: " + l_order.etag) + end + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.write_headers_string (h.string) + res.write_string (j.representation) end + else + handle_resource_not_found_response ("The following resource" + orig_path + " is not found ", ctx, req, res) end + end end do_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) @@ -82,38 +84,37 @@ feature -- HTTP Methods jv : detachable JSON_VALUE h : EWF_HEADER do - fixme ("TODO handle an Internal Server Error") - fixme ("Refactor the code, create new abstractions") - fixme ("Add Header Date to the response") - fixme ("Put implememntation is wrong!!!!") - req.input.read_stream (req.content_length_value.as_integer_32) - l_post := req.input.last_string - l_order := extract_order_request(l_post) - fixme ("TODO move to a service method") - if l_order /= Void and then db_access.orders.has_key (l_order.id) then - update_order( l_order) - create h.make - h.put_status (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 - if attached req.http_host as host then - l_location := "http://"+host +req.request_uri+"/" + l_order.id - h.add_header ("Location:"+ l_location) - end - jv ?= json.value (l_order) - if jv /= Void then - h.put_content_length (jv.representation.count) - res.set_status_code (ok) - res.write_headers_string (h.string) - res.write_string (jv.representation) - end - else - handle_bad_request_response(l_post +"%N is not a valid ORDER, maybe the order does not exist in the system",req.content_type,res) + fixme ("TODO handle an Internal Server Error") + fixme ("Refactor the code, create new abstractions") + fixme ("Add Header Date to the response") + fixme ("Put implementation is wrong!!!!") + req.input.read_stream (req.content_length_value.as_integer_32) + l_post := req.input.last_string + l_order := extract_order_request(l_post) + fixme ("TODO move to a service method") + if l_order /= Void and then db_access.orders.has_key (l_order.id) then + update_order( l_order) + 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 + if attached req.http_host as host then + l_location := "http://"+host +req.request_uri+"/" + l_order.id + h.add_header ("Location:"+ l_location) + end + jv ?= json.value (l_order) + if jv /= Void then + h.put_content_length (jv.representation.count) + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.write_headers_string (h.string) + res.write_string (jv.representation) + end + else + handle_bad_request_response (l_post +"%N is not a valid ORDER, maybe the order does not exist in the system", ctx, req, res) end - + end do_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) local @@ -121,129 +122,123 @@ feature -- HTTP Methods id: STRING h : EWF_HEADER do - fixme ("TODO handle an Internal Server Error") - fixme ("Refactor the code, create new abstractions") - if attached req.orig_path_info as orig_path then - uri := orig_path.split ('/') - id := uri.at (3) - if db_access.orders.has_key (id) then - delete_order( id) - create h.make - h.put_status (no_content) - 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 - res.set_status_code (no_content) - res.write_headers_string (h.string) - else - handle_resource_not_found_response (orig_path + " not found in this server",req.content_type, res) + fixme ("TODO handle an Internal Server Error") + fixme ("Refactor the code, create new abstractions") + if attached req.orig_path_info as orig_path then + uri := orig_path.split ('/') + id := uri.at (3) + if db_access.orders.has_key (id) then + delete_order( id) + 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_headers_string (h.string) + else + handle_resource_not_found_response (orig_path + " not found in this server", ctx, req, res) end - end - - do_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - -- 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 - -- 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 - l_order : detachable ORDER - do - req.input.read_stream (req.content_length_value.as_integer_32) - l_post := req.input.last_string - l_order := extract_order_request(l_post) - if l_order /= Void 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", req.content_type,res) end end + do_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- 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 + -- 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_stream (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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; l_order : ORDER) local h: EWF_HEADER l_msg : STRING - jv : detachable JSON_VALUE l_location : STRING do create h.make - h.put_status (created) - h.put_content_type ("application/json") - jv ?= json.value (l_order) - if jv /= Void 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.add_header ("Location:"+ l_location) - end - 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 - res.set_status_code (created) - res.write_headers_string (h.string) - res.write_string (l_msg) + 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.add_header ("Date:" + time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT") + end + res.set_status_code ({HTTP_STATUS_CODE}.created) + res.write_headers_string (h.string) + res.write_string (l_msg) end end -feature -- Implementation Repository Layer +feature {NONE} -- Implementation Repository Layer - save_order ( an_order : ORDER) - -- save the order to the repository + 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) + 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 - update_order ( an_order : ORDER) - -- update the order to the repository + 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 + 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 + -- extract an object Order from the request, or Void + -- if the request is invalid local joc : JSON_ORDER_CONVERTER parser : JSON_PARSER - l_order : detachable ORDER - jv : detachable JSON_VALUE do create joc.make json.add_converter(joc) create parser.make_parser (l_post) - jv ?= parser.parse - if jv /= Void and parser.is_parsed then - l_order ?= json.object (jv, "ORDER") - Result := l_order + 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 diff --git a/examples/restbucks/src/restbucks_server.e b/examples/restbucks/src/restbucks_server.e index 8f331f93..5b01a28c 100644 --- a/examples/restbucks/src/restbucks_server.e +++ b/examples/restbucks/src/restbucks_server.e @@ -16,15 +16,11 @@ inherit DEFAULT_WGI_APPLICATION - WGI_RESPONSE_STATUS_CODES - - create make feature {NONE} -- Initialization - make do initialize_router @@ -33,7 +29,7 @@ feature {NONE} -- Initialization create_router do - create router.make (5) + create router.make (2) end setup_router @@ -48,32 +44,31 @@ feature {NONE} -- Initialization feature -- Execution execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - -- 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. - + -- 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 : EWF_HEADER l_description : STRING l_api_doc : STRING do - if req.content_length_value > 0 then - req.input.read_stream (req.content_length_value.as_integer_32) - end - create h.make - h.put_status (method_not_allowed) - h.put_content_type ("application/json") - 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.add_header ("Date:"+ ((create{HTTP_DATE_TIME_UTILITIES}).now_utc).formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT") - res.set_status_code (method_not_allowed) - res.write_headers_string (h.string) - res.write_string (l_description) + if req.content_length_value > 0 then + req.input.read_stream (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_headers_string (h.string) + res.write_string (l_description) end note - copyright: "2011-2011, Eiffel Software and others" + copyright: "2011-2011, Javier Velilla and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/examples/restbucks/src/wgi_response_status_codes.e b/examples/restbucks/src/wgi_response_status_codes.e deleted file mode 100644 index ac07b825..00000000 --- a/examples/restbucks/src/wgi_response_status_codes.e +++ /dev/null @@ -1,258 +0,0 @@ -note - description: "Based on http://en.wikipedia.org/wiki/List_of_HTTP_status_codes." - author: "" - date: "$Date$" - revision: "$Revision$" - -deferred class - WGI_RESPONSE_STATUS_CODES - -feature -- 1xx Informational - - Continue : INTEGER = 100 - --This means that the server has received the request headers, and that the client should proceed to send the request body - --(in the case of a request for which a body needs to be sent; for example, a POST request). - --If the request body is large, sending it to a server when a request has already been rejected based upon inappropriate headers is inefficient. - --To have a server check if the request could be accepted based on the request's headers alone, - --a client must send Expect: 100-continue as a header in its initial request[2] and check if a 100 Continue status code is received in response - --before continuing (or receive 417 Expectation Failed and not continue). - - Switching_Protocols : INTEGER = 101 - --This means the requester has asked the server to switch protocols and the server is acknowledging that it will do so. - - Processing : INTEGER = 102 -- (WebDAV) (RFC 2518) - --As a WebDAV request may contain many sub-requests involving file operations, it may take a long time to complete the request. - --This code indicates that the server has received and is processing the request, but no response is available yet. - --This prevents the client from timing out and assuming the request was lost. - - Checkpoint : INTEGER = 103 - --This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT or POST requests. - - Request_URI_too_long_ie7 : INTEGER = 122 - --This is a non-standard IE7-only code which means the URI is longer than a maximum of 2083 characters - - -feature -- 2xx Success - - OK : INTEGER = 200 - --Standard response for successful HTTP requests. The actual response will depend on the request method used. - --In a GET request, the response will contain an entity corresponding to the requested resource. - --In a POST request the response will contain an entity describing or containing the result of the action. - - Created : INTEGER = 201 - --The request has been fulfilled and resulted in a new resource being created. - - Accepted : INTEGER = 202 - --The request has been accepted for processing, but the processing has not been completed. - --The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. - - Non_Authoritative_Information : INTEGER = 203 --(since HTTP/1.1) - --The server successfully processed the request, but is returning information that may be from another source. - - No_Content : INTEGER = 204 - --The server successfully processed the request, but is not returning any content. - - Reset_Content : INTEGER = 205 - --The server successfully processed the request, but is not returning any content. - --Unlike a 204 response, this response requires that the requester reset the document view. - - - Partial_Content : INTEGER = 206 - --The server is delivering only part of the resource due to a range header sent by the client. - --The range header is used by tools like wget to enable resuming of interrupted downloads, - --or split a download into multiple simultaneous streams. - - Multi_Status : INTEGER = 207 --(WebDAV) (RFC 4918) - --The message body that follows is an XML message and can contain a number of separate response codes, - -- depending on how many sub-requests were made. - - IM_Used : INTEGER = 226 -- (RFC 3229) - --The server has fulfilled a GET request for the resource, and the response is a representation of the result of one - --or more instance-manipulations applied to the current instance. - -feature -- 3xx Redirection - - - Multiple_Choices : INTEGER = 300 - --Indicates multiple options for the resource that the client may follow. - --It, for instance, could be used to present different format options for video, list files with different extensions, or word sense disambiguation. - - Moved_Permanently : INTEGER = 301 - --This and all future requests should be directed to the given URI. - - Found : INTEGER = 302 - --This is an example of industrial practice contradicting the standard. - --HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was "Moved Temporarily"), - --but popular browsers implemented 302 with the functionality of a 303 See Other. - --Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours. - --However, some Web applications and frameworks use the 302 status code as if it were the 303. - - See_Other : INTEGER = 303 -- (since HTTP/1.1) - --The response to the request can be found under another URI using a GET method. - --When received in response to a POST (or PUT/DELETE), it should be assumed that the server - --has received the data and the redirect should be issued with a separate GET message. - - Not_Modified : INTEGER = 304 - --Indicates the resource has not been modified since last requested. - --Typically, the HTTP client provides a header like the If-Modified-Since header to provide a time against which to compare. - --Using this saves bandwidth and reprocessing on both the server and client, - --as only the header data must be sent and received in comparison to the entirety of the page being re-processed by the server, - --then sent again using more bandwidth of the server and client. - - Use_Proxy : INTEGER = 305 --(since HTTP/1.1) - --Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons. - - Switch_Proxy : INTEGER = 306 - --No longer used. Originally meant "Subsequent requests should use the specified proxy." - - Temporary_Redirect : INTEGER = 307 --(since HTTP/1.1) - --In this occasion, the request should be repeated with another URI, but future requests can still use the original URI. - --In contrast to 303, the request method should not be changed when reissuing the original request. - --For instance, a POST request must be repeated using another POST request. - - Resume_Incomplete : INTEGER = 308 - --This code is used in the Resumable HTTP Requests Proposal to resume aborted PUT or POST requests. - -feature -- 4xx Client Error - - Bad_Request : INTEGER = 400 - --The request cannot be fulfilled due to bad syntax. - - Unauthorized : INTEGER = 401 - --Similar to 403 Forbidden, but specifically for use when authentication is possible but has failed or not yet been provided. - --The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource. - --See Basic access authentication and Digest access authentication. - - Payment_Required : INTEGER = 402 - --Reserved for future use.The original intention was that this code might be used as part of some form of digital cash or micropayment scheme, - --but that has not happened, and this code is not usually used. - --As an example of its use, however, Apple's MobileMe service generates a 402 error ("httpStatusCode:402" in the Mac OS X Console log) if the MobileMe account is delinquent. - - Forbidden : INTEGER = 403 - --The request was a legal request, but the server is refusing to respond to it. - --Unlike a 401 Unauthorized response, authenticating will make no difference. - - Not_Found : INTEGER = 404 - --The requested resource could not be found but may be available again in the future. - --Subsequent requests by the client are permissible. - - Method_Not_Allowed : INTEGER = 405 - --A request was made of a resource using a request method not supported by that resource; - --for example, using GET on a form which requires data to be presented via POST, or using PUT on a read-only resource. - - Not_Acceptable : INTEGER = 406 - --The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request. - - Proxy_Authentication_Required : INTEGER = 407 - --The client must first authenticate itself with the proxy. - - Request_Timeout : INTEGER = 408 - --The server timed out waiting for the request. According to W3 HTTP specifications: - --"The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time." - - Conflict : INTEGER = 409 - --Indicates that the request could not be processed because of conflict in the request, such as an edit conflict. - - Gone : INTEGER = 410 - --Indicates that the resource requested is no longer available and will not be available again. - --This should be used when a resource has been intentionally removed and the resource should be purged. - -- Upon receiving a 410 status code, the client should not request the resource again in the future. - -- Clients such as search engines should remove the resource from their indices. - --Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead. - - Length_Required : INTEGER = 411 - --The request did not specify the length of its content, which is required by the requested resource. - - Precondition_Failed : INTEGER = 412 - --The server does no t meet one of the preconditions that the requester put on the request. - - Request_Entity_Too_Large : INTEGER = 413 - --The request is larger than the server is willing or able to process. - - Request_URI_Too_Long : INTEGER = 414 - --The URI provided was too long for the server to process. - - Unsupported_Media_Type : INTEGER = 415 - --The request entity has a media type which the server or resource does not support. - --For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format. - - Requested_Range_Not_Satisfiable : INTEGER = 416 - --The client has asked for a portion of the file, but the server cannot supply that portion. - --For example, if the client asked for a part of the file that lies beyond the end of the file. - - Expectation_Failed : INTEGER = 417 - --The server cannot meet the requirements of the Expect request-header field. - - Im_a_teapot : INTEGER = 418 --(RFC 2324) - --This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, - --Hyper Text Coffee Pot Control Protocol, and is not expected to be implemented by actual HTTP servers. - - Unprocessable_Entity : INTEGER = 422 --(WebDAV) (RFC 4918) - --The request was well-formed but was unable to be followed due to semantic errors. - - Locked : INTEGER = 423 --(WebDAV) (RFC 4918) - --The resource that is being accessed is locked. - - Failed_Dependency : INTEGER = 424 --(WebDAV) (RFC 4918) - --The request failed due to failure of a previous request (e.g. a PROPPATCH). - - Unordered_Collection : INTEGER = 425 --(RFC 3648) - --Defined in drafts of "WebDAV Advanced Collections Protocol", - --but not present in "Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol". - - Upgrade_Required : INTEGER = 426 -- (RFC 2817) - --The client should switch to a different protocol such as TLS/1.0. - - No_Response : INTEGER = 444 - --A Nginx HTTP server extension. The server returns no information to the client and closes the connection (useful as a deterrent for malware). - - Retry_With : INTEGER = 449 - --A Microsoft extension. The request should be retried after performing the appropriate action. - - Blocked_by_Windows_Parental_Controls : INTEGER = 450 - --A Microsoft extension. This error is given when Windows Parental Controls are turned on and are blocking access to the given webpage. - - Client_Closed_Request : INTEGER = 499 - --An Nginx HTTP server extension. - --This code is introduced to log the case when the connection is closed by client while HTTP server is processing its request, - -- making server unable to send the HTTP header back. - -feature -- 5xx Server Error - Internal_Server_Error : INTEGER = 500 - --A generic error message, given when no more specific message is suitable. - - Not_Implemented : INTEGER = 501 - --The server either does not recognise the request method, or it lacks the ability to fulfill the request. - - Bad_Gateway : INTEGER = 502 - --The server was acting as a gateway or proxy and received an invalid response from the upstream server. - - Service_Unavailable : INTEGER = 503 - --The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state. - - Gateway_Timeout : INTEGER = 504 - --The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. - - HTTP_Version_Not_Supported : INTEGER = 505 - --The server does not support the HTTP protocol version used in the request. - - Variant_Also_Negotiates : INTEGER = 506 --(RFC 2295) - --Transparent content negotiation for the request results in a circular reference. - - Insufficient_Storage : INTEGER = 507 -- (WebDAV)(RFC 4918) - --The server is unable to store the representation needed to complete the request. - - Bandwidth_Limit_Exceeded : INTEGER = 509 -- (Apache bw/limited extension) - --This status code, while used by many servers, is not specified in any RFCs. - - Not_Extended : INTEGER = 510 -- (RFC 2774) - --Further extensions to the request are required for the server to fulfill it.[20] - - network_read_timeout_error : INTEGER = 598 --598 (Informal convention) - --This status code is not specified in any RFCs, but is used by some HTTP proxies to signal a network read - --timeout behind the proxy to a client in front of the proxy. - - network_connect_timeout_error : INTEGER = 599 - --This status code is not specified in any RFCs, but is used by some HTTP proxies to signal a - --network connect timeout behind the proxy to a client in front of the proxy. -end diff --git a/library/server/ewsgi/src/support/ewf_header.e b/library/server/ewsgi/src/support/ewf_header.e index 3c867595..8b01783b 100644 --- a/library/server/ewsgi/src/support/ewf_header.e +++ b/library/server/ewsgi/src/support/ewf_header.e @@ -207,6 +207,23 @@ feature -- Content related header feature -- Others + put_date (s: READABLE_STRING_8) + do + put_header_key_value ("Date", s) + end + + put_current_date + -- Put current date time with "Date" header + do + put_utc_date (create {DATE_TIME}.make_now_utc) + end + + put_utc_date (dt: DATE_TIME) + -- Put UTC date time `dt' with "Date" header + do + put_date (dt.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT") + end + put_expires (n: INTEGER) do put_header_key_value ("Expires", n.out) diff --git a/library/server/request/router/src/misc/request_resource_handler_helper.e b/library/server/request/router/src/misc/request_resource_handler_helper.e index 013507c5..6b981878 100644 --- a/library/server/request/router/src/misc/request_resource_handler_helper.e +++ b/library/server/request/router/src/misc/request_resource_handler_helper.e @@ -1,249 +1,231 @@ note - description: "Work in progress Common abstraction to handle REST methods" + description: "Work in progress Common abstraction to handle RESTfull methods" author: "" date: "$Date$" revision: "$Revision$" class - REQUEST_RESOURCE_HANDLER_HELPER[C -> REQUEST_HANDLER_CONTEXT] - -inherit - HTTP_STATUS_CODE + REQUEST_RESOURCE_HANDLER_HELPER [C -> REQUEST_HANDLER_CONTEXT] feature -- Execute template + execute_methods (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- Execute request and dispatch according to the request method + local + m: READABLE_STRING_8 do - if req.request_method.same_string ("GET") then - execute_get (ctx,req,res) - elseif req.request_method.same_string ("PUT") then - execute_put (ctx,req,res) - elseif req.request_method.same_string ("DELETE") then - execute_delete (ctx,req,res) - elseif req.request_method.same_string ("POST") then - execute_post (ctx,req,res) - elseif req.request_method.same_string ("TRACE") then - execute_trace (ctx,req,res) - elseif req.request_method.same_string ("OPTIONS") then - execute_options (ctx,req,res) - elseif req.request_method.same_string ("HEAD") then - execute_head (ctx,req,res) - elseif req.request_method.same_string ("CONNECT") then - execute_connect (ctx,req,res) --- elseif req.request_method.is_valid_extension_method then --- execute_extension_method (req,res) - end - end - - -feature-- Method Post - execute_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - if req.content_length_value > 0 then - do_post (ctx,req,res) + m := req.request_method + if m.same_string ("GET") then + execute_get (ctx, req, res) + elseif m.same_string ("PUT") then + execute_put (ctx, req, res) + elseif m.same_string ("DELETE") then + execute_delete (ctx, req, res) + elseif m.same_string ("POST") then + execute_post (ctx, req, res) + elseif m.same_string ("TRACE") then + execute_trace (ctx, req, res) + elseif m.same_string ("OPTIONS") then + execute_options (ctx, req, res) + elseif m.same_string ("HEAD") then + execute_head (ctx, req, res) + elseif m.same_string ("CONNECT") then + execute_connect (ctx, req, res) else - handle_bad_request_response("Bad request, content_lenght empty", req.content_type, res) + --| Eventually handle other methods... end rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + handle_internal_server_error ("Internal Server Error", ctx, req, res) + end + +feature -- Method Post + + execute_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + if req.content_length_value > 0 then + do_post (ctx, req, res) + else + handle_bad_request_response ("Bad request, content_length empty", ctx, req, res) + end end do_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method POST not implemented", req.content_type, res) + handle_not_implemented ("Method POST not implemented", ctx, req, res) end +feature-- Method Put - -feature-- Method Put execute_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - if req.content_length_value > 0 then - do_put (ctx,req,res) + do + if req.content_length_value > 0 then + do_put (ctx, req, res) else - handle_bad_request_response("Bad request, content_lenght empty", req.content_type, res) + handle_bad_request_response ("Bad request, content_length empty", ctx, req, res) end - rescue - handle_internal_server_error("Internal Server Error", req.content_type,res) end do_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method PUT not implemented", req.content_type,res) + handle_not_implemented ("Method PUT not implemented", ctx, req, res) end feature -- Method Get + execute_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_get (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + do + do_get (ctx, req, res) end do_get (ctx: C;req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method HEAD not implemented", req.content_type, res) + handle_not_implemented ("Method HEAD not implemented", ctx, req, res) end feature -- Method DELETE + execute_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_delete (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + do + do_delete (ctx, req, res) end do_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method DELETE not implemented", req.content_type, res) + handle_not_implemented ("Method DELETE not implemented", ctx, req, res) end feature -- Method CONNECT + execute_connect (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_connect (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + do + do_connect (ctx, req, res) end do_connect (ctx: C;req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method CONNECT not implemented", req.content_type, res) + handle_not_implemented ("Method CONNECT not implemented", ctx, req, res) end feature -- Method HEAD + execute_head (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_head (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error", req.content_type, res) + do + do_head (ctx, req, res) end do_head (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method HEAD not implemented", req.content_type, res) + handle_not_implemented ("Method HEAD not implemented", ctx, req, res) end feature -- Method OPTIONS + execute_options (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_options (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + do + do_options (ctx, req, res) end do_options (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method OPTIONS not implemented", req.content_type,res) + handle_not_implemented ("Method OPTIONS not implemented", ctx, req, res) end feature -- Method TRACE + execute_trace (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_trace (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error", req.content_type, res) + do + do_trace (ctx, req, res) end do_trace (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method TRACE not implemented", req.content_type,res) + handle_not_implemented ("Method TRACE not implemented", ctx, req, res) end feature -- Method Extension Method + execute_extension_method (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) - do - do_extension_method (ctx,req,res) - rescue - handle_internal_server_error("Internal Server Error",req.content_type,res) + do + do_extension_method (ctx, req, res) end do_extension_method (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) do - handle_not_implemented ("Method EXTENSION METHOD not implemented",req.content_type, res) + handle_not_implemented ("Method EXTENSION method not implemented", ctx, req, res) end feature -- Handle responses - handle_bad_request_response (a_description:STRING; content_type : detachable READABLE_STRING_32 ; res: WGI_RESPONSE_BUFFER ) + + handle_bad_request_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) local h : EWF_HEADER do - create h.make - h.put_status (bad_request) - if attached content_type 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.add_header ("Date:"+ get_date) - res.set_status_code (bad_request) - res.write_headers_string (h.string) - res.write_string (a_description) + create h.make + h.put_status ({HTTP_STATUS_CODE}.bad_request) + if attached ctx.request_content_type (Void) 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}.bad_request) + res.write_headers_string (h.string) + res.write_string (a_description) end - - - handle_internal_server_error (a_description:STRING; content_type : detachable READABLE_STRING_32 ; res: WGI_RESPONSE_BUFFER ) + handle_internal_server_error (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) local h : EWF_HEADER do - create h.make - h.put_status (internal_server_error) - if attached content_type 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.add_header ("Date:"+ get_date) - res.set_status_code (internal_server_error) - res.write_headers_string (h.string) - res.write_string (a_description) + create h.make + h.put_status ({HTTP_STATUS_CODE}.internal_server_error) + if attached ctx.request_content_type (Void) 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}.internal_server_error) + res.write_headers_string (h.string) + res.write_string (a_description) end - - - handle_not_implemented (a_description:STRING; content_type : detachable READABLE_STRING_32; res: WGI_RESPONSE_BUFFER ) + handle_not_implemented (a_description: STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) local h : EWF_HEADER do - create h.make - h.put_status (not_implemented) - if attached content_type 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.add_header ("Date:"+ get_date) - res.set_status_code (not_implemented) - res.write_headers_string (h.string) - res.write_string (a_description) + create h.make + h.put_status ({HTTP_STATUS_CODE}.not_implemented) + if attached ctx.request_content_type (Void) 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_implemented) + res.write_headers_string (h.string) + res.write_string (a_description) end - - handle_resource_not_found_response (a_description:STRING; content_type : detachable READABLE_STRING_32; res: WGI_RESPONSE_BUFFER) + handle_resource_not_found_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) local h : EWF_HEADER do - create h.make - h.put_status (not_found) - if attached content_type 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.add_header ("Date:"+ get_date) - res.set_status_code (not_found) - res.write_headers_string (h.string) - res.write_string (a_description) - end - -feature -- Date Utilities - get_date : STRING - do - Result := ((create{HTTP_DATE_TIME_UTILITIES}).now_utc).formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT" + create h.make + h.put_status ({HTTP_STATUS_CODE}.not_found) + if attached ctx.request_content_type (Void) 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_found) + res.write_headers_string (h.string) + res.write_string (a_description) end note