From 888bc6152262cc885e1a32200dfcd8f832724d0b Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 22 Sep 2011 09:29:59 -0300 Subject: [PATCH] Initial import, work in progress restbuck example. Only support create a resource --- examples/restbucks/restbucks-safe.ecf | 25 ++ examples/restbucks/restbucks.rc | 1 + .../restbucks/src/database/database_api.e | 21 ++ .../src/database/shared_database_api.e | 14 + examples/restbucks/src/domain/item.e | 87 ++++++ .../restbucks/src/domain/item_constants.e | 51 ++++ .../src/domain/json_order_converter.e | 166 +++++++++++ examples/restbucks/src/domain/order.e | 109 ++++++++ .../restbucks/src/domain/order_validation.e | 54 ++++ .../src/domain/shared_order_validation.e | 16 ++ .../restbucks/src/resource/order_handler.e | 184 +++++++++++++ examples/restbucks/src/restbucks_server.e | 199 ++++++++++++++ .../restbucks/src/wgi_response_status_codes.e | 258 ++++++++++++++++++ 13 files changed, 1185 insertions(+) create mode 100644 examples/restbucks/restbucks-safe.ecf create mode 100644 examples/restbucks/restbucks.rc create mode 100644 examples/restbucks/src/database/database_api.e create mode 100644 examples/restbucks/src/database/shared_database_api.e create mode 100644 examples/restbucks/src/domain/item.e create mode 100644 examples/restbucks/src/domain/item_constants.e create mode 100644 examples/restbucks/src/domain/json_order_converter.e create mode 100644 examples/restbucks/src/domain/order.e create mode 100644 examples/restbucks/src/domain/order_validation.e create mode 100644 examples/restbucks/src/domain/shared_order_validation.e create mode 100644 examples/restbucks/src/resource/order_handler.e create mode 100644 examples/restbucks/src/restbucks_server.e create mode 100644 examples/restbucks/src/wgi_response_status_codes.e diff --git a/examples/restbucks/restbucks-safe.ecf b/examples/restbucks/restbucks-safe.ecf new file mode 100644 index 00000000..4651633a --- /dev/null +++ b/examples/restbucks/restbucks-safe.ecf @@ -0,0 +1,25 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + diff --git a/examples/restbucks/restbucks.rc b/examples/restbucks/restbucks.rc new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/restbucks/restbucks.rc @@ -0,0 +1 @@ + diff --git a/examples/restbucks/src/database/database_api.e b/examples/restbucks/src/database/database_api.e new file mode 100644 index 00000000..1ebeaffa --- /dev/null +++ b/examples/restbucks/src/database/database_api.e @@ -0,0 +1,21 @@ +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] + +end diff --git a/examples/restbucks/src/database/shared_database_api.e b/examples/restbucks/src/database/shared_database_api.e new file mode 100644 index 00000000..0a27b7cd --- /dev/null +++ b/examples/restbucks/src/database/shared_database_api.e @@ -0,0 +1,14 @@ +note + description: "Summary description for {SHARED_DATABASE_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + SHARED_DATABASE_API +feature + db_access: DATABASE_API + once + create Result.make + end +end diff --git a/examples/restbucks/src/domain/item.e b/examples/restbucks/src/domain/item.e new file mode 100644 index 00000000..8d5c28d6 --- /dev/null +++ b/examples/restbucks/src/domain/item.e @@ -0,0 +1,87 @@ +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 +end diff --git a/examples/restbucks/src/domain/item_constants.e b/examples/restbucks/src/domain/item_constants.e new file mode 100644 index 00000000..07dfc0d0 --- /dev/null +++ b/examples/restbucks/src/domain/item_constants.e @@ -0,0 +1,51 @@ +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 +end diff --git a/examples/restbucks/src/domain/json_order_converter.e b/examples/restbucks/src/domain/json_order_converter.e new file mode 100644 index 00000000..48dcafbe --- /dev/null +++ b/examples/restbucks/src/domain/json_order_converter.e @@ -0,0 +1,166 @@ +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 + lstr1, lstr2, lstr3 : detachable STRING_32 + q: detachable INTEGER_8 + o: ORDER + i : ITEM + l_val : detachable JSON_ARRAY + l_array : detachable ARRAYED_LIST[JSON_VALUE] + jv : detachable JSON_OBJECT + 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) + + if l_val /= void 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) + 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 + +end diff --git a/examples/restbucks/src/domain/order.e b/examples/restbucks/src/domain/order.e new file mode 100644 index 00000000..13a8b54d --- /dev/null +++ b/examples/restbucks/src/domain/order.e @@ -0,0 +1,109 @@ +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 -- 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 + +end diff --git a/examples/restbucks/src/domain/order_validation.e b/examples/restbucks/src/domain/order_validation.e new file mode 100644 index 00000000..a4cc18e5 --- /dev/null +++ b/examples/restbucks/src/domain/order_validation.e @@ -0,0 +1,54 @@ +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 + + +end diff --git a/examples/restbucks/src/domain/shared_order_validation.e b/examples/restbucks/src/domain/shared_order_validation.e new file mode 100644 index 00000000..90d09ec7 --- /dev/null +++ b/examples/restbucks/src/domain/shared_order_validation.e @@ -0,0 +1,16 @@ +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 + +end diff --git a/examples/restbucks/src/resource/order_handler.e b/examples/restbucks/src/resource/order_handler.e new file mode 100644 index 00000000..d7c240f6 --- /dev/null +++ b/examples/restbucks/src/resource/order_handler.e @@ -0,0 +1,184 @@ +note + description: "Summary description for {ORDER_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + ORDER_HANDLER[C -> REQUEST_HANDLER_CONTEXT] +inherit + REQUEST_HANDLER[C] + SHARED_DATABASE_API + SHARED_EJSON + REFACTORING_HELPER + SHARED_ORDER_VALIDATION + WGI_RESPONSE_STATUS_CODES + +feature -- execute + execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + -- Execute request handler + do + if req.request_method.same_string ("GET") then +-- pre_process_get (ctx, a_format, a_args) + elseif req.request_method.same_string ("PUT") then +-- pre_process_put (ctx, a_format, a_args) + elseif req.request_method.same_string ("DELETE") then +-- pre_process_delete (ctx, a_format, a_args) + elseif req.request_method.same_string ("POST") then + process_post (ctx,req,res) + else + -- TODO HANDLE METHOD NOT SUPPORTED + end + end + +feature -- HTTP Methods + + process_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + l_values: HASH_TABLE [STRING_32, STRING] + l_missings: LINKED_LIST [STRING] + l_full: BOOLEAN + l_post: STRING + l_location : STRING + l_msg : STRING + l_order : detachable ORDER + 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") + if req.content_length_value > 0 then + 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 then + save_order( l_order) + 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 + res.set_status_code (created) + res.write_headers_string (h.string) + res.write_string (l_msg) + end + else +-- handle_bad_request_response(l_post +"%N is not a valid ORDER",ctx.output) + end + else +-- handle_bad_request_response("Bad request, content_lenght empty",ctx.output) + end + end + + +feature -- Implementation + + 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 + +-- 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 + 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 + end + end + + +-- handle_bad_request_response (a_description:STRING; an_output: HTTPD_SERVER_OUTPUT ) +-- local +-- rep: detachable REST_RESPONSE +-- do +-- create rep.make (path) +-- rep.headers.put_status (rep.headers.bad_request) +-- rep.headers.put_content_type_application_json +-- rep.set_message (a_description) +-- an_output.put_string (rep.string) +-- rep.recycle +-- end + +-- handle_conflic_request_response (a_description:STRING; an_output: HTTPD_SERVER_OUTPUT ) +-- local +-- rep: detachable REST_RESPONSE +-- do +-- create rep.make (path) +-- rep.headers.put_status (rep.headers.conflict) +-- rep.headers.put_content_type_application_json +-- rep.set_message (a_description) +-- an_output.put_string (rep.string) +-- rep.recycle +-- end + + +-- handle_resource_not_found_response (a_description:STRING; an_output: HTTPD_SERVER_OUTPUT ) +-- local +-- rep: detachable REST_RESPONSE +-- do +-- create rep.make (path) +-- rep.headers.put_status (rep.headers.not_found) +-- rep.headers.put_content_type_application_json +-- rep.set_message (a_description) +-- an_output.put_string (rep.string) +-- rep.recycle +-- end + + +-- handle_method_not_supported_response (ctx :REST_REQUEST_CONTEXT) +-- local +-- rep: detachable REST_RESPONSE +-- do +-- create rep.make (path) +-- rep.headers.put_status (rep.headers.method_not_allowed) +-- rep.headers.put_content_type_application_json +-- ctx.output.put_string (rep.string) +-- rep.recycle +-- end + +end diff --git a/examples/restbucks/src/restbucks_server.e b/examples/restbucks/src/restbucks_server.e new file mode 100644 index 00000000..34bf2392 --- /dev/null +++ b/examples/restbucks/src/restbucks_server.e @@ -0,0 +1,199 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + RESTBUCKS_SERVER + +inherit + ANY + + URI_TEMPLATE_ROUTED_APPLICATION + + ROUTED_APPLICATION_HELPER + + DEFAULT_WGI_APPLICATION + +create + make + +feature {NONE} -- Initialization + + + make + do + initialize_router + make_and_launch + end + + create_router + do + create router.make (5) + 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: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + local + h: EWF_HEADER + l_url: STRING + e: EXECUTION_ENVIRONMENT + n: INTEGER + i: INTEGER + do + create h.make + l_url := req.script_url ("/home") + n := 3 + h.put_refresh (l_url, 5, 200) + res.set_status_code (200) + res.write_headers_string (h.string) + from + create e + until + n = 0 + loop + if n > 1 then + res.write_string ("Redirected to " + l_url + " in " + n.out + " seconds :%N") + else + res.write_string ("Redirected to " + l_url + " in 1 second :%N") + end + res.flush + from + i := 1 + until + i = 1001 + loop + res.write_string (".") + if i \\ 100 = 0 then + res.write_string ("%N") + end + res.flush + e.sleep (1_000_000) + i := i + 1 + end + res.write_string ("%N") + n := n - 1 + end + res.write_string ("You are now being redirected...%N") + res.flush + end + + execute_home (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + res.write_header (200, <<["Content-Type", "text/html"]>>) + res.write_string ("Hello World ?!%N") + res.write_string ("

Please try the following links

%N") + + if attached req.item ("REQUEST_COUNT") as rqc then + res.write_string ("request #"+ rqc.as_string + "%N") + end + res.write_string ("%N") + end + + execute_hello (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_name: detachable READABLE_STRING_32; ctx: REQUEST_HANDLER_CONTEXT) + local + l_response_content_type: detachable STRING + msg: STRING + h: EWF_HEADER + content_type_supported: ARRAY [STRING] + do + if a_name /= Void then + msg := "Hello %"" + a_name + "%" !%N" + else + msg := "Hello anonymous visitor !%N" + end + content_type_supported := <<{HTTP_CONSTANTS}.json_app, {HTTP_CONSTANTS}.html_text, {HTTP_CONSTANTS}.xml_text, {HTTP_CONSTANTS}.plain_text>> + inspect ctx.request_format_id ("format", content_type_supported) + when {HTTP_FORMAT_CONSTANTS}.json then + l_response_content_type := {HTTP_CONSTANTS}.json_app + msg := "{%N%"application%": %"/hello%",%N %"message%": %"" + msg + "%" %N}" + when {HTTP_FORMAT_CONSTANTS}.html then + l_response_content_type := {HTTP_CONSTANTS}.html_text + when {HTTP_FORMAT_CONSTANTS}.xml then + l_response_content_type := {HTTP_CONSTANTS}.xml_text + msg := "/hello" + msg + "%N" + when {HTTP_FORMAT_CONSTANTS}.text then + l_response_content_type := {HTTP_CONSTANTS}.plain_text + else + execute_content_type_not_allowed (req, res, content_type_supported, + <<{HTTP_FORMAT_CONSTANTS}.json_name, {HTTP_FORMAT_CONSTANTS}.html_name, {HTTP_FORMAT_CONSTANTS}.xml_name, {HTTP_FORMAT_CONSTANTS}.text_name>> + ) + end + if l_response_content_type /= Void then + create h.make + h.put_status (200) + h.put_content_type (l_response_content_type) + h.put_content_length (msg.count) + res.set_status_code (200) + res.write_headers_string (h.string) +-- res.write_header (200, << +-- ["Content-Type", l_response_content_type], +-- ["Content-Length", msg.count.out +-- >>) + res.write_string (msg) + end + end + + handle_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, Void, ctx) + end + + handle_anonymous_hello (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, ctx.string_parameter ("name"), ctx) + end + + handle_method_any (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, req.request_method, ctx) + end + + handle_method_get (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, "GET", ctx) + end + + + handle_method_post (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, "POST", ctx) + end + + handle_method_get_or_post (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute_hello (req, res, "GET or POST", ctx) + end + + + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/examples/restbucks/src/wgi_response_status_codes.e b/examples/restbucks/src/wgi_response_status_codes.e new file mode 100644 index 00000000..ac07b825 --- /dev/null +++ b/examples/restbucks/src/wgi_response_status_codes.e @@ -0,0 +1,258 @@ +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