From b790c7fd21b81d4174cb72a37ccefc848311b3e9 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 10 Jun 2015 10:59:24 +0200 Subject: [PATCH 01/36] cosmetic, cleaning. --- CHANGELOGS.txt | 39 ++----------------- MIGRATION.md | 4 +- .../standalone/src/httpd/httpd-safe.ecf | 1 - 3 files changed, 6 insertions(+), 38 deletions(-) diff --git a/CHANGELOGS.txt b/CHANGELOGS.txt index da54ebf3..6f4f3c1e 100644 --- a/CHANGELOGS.txt +++ b/CHANGELOGS.txt @@ -1,38 +1,7 @@ History for Eiffel-Web-Framework +[2015-06-10] + * Updated EWF design to better support concurrency, including SCOOP via + the new standalone connector. -[2011-09-23] Jocelyn - * library "ewsgi": - - NEW simple autotest cases using Nino web server - -fixed issue with RAW_POST_DATA being added in form_data_parameters - instead of meta_variables ... - - Implemented WGI_VALUE for parameter's type (query_parameter, - form_data_parameter, item ...) - * Nino connector: added feature to shutdown the server from the WGI application - * NEW library "http_client": a new library to perform simple http requests - such as get, head, post, put, ... (currently implemented with Eiffel cURL) - * NEW library "http_authorization": added simple library to support - HTTP_AUTHORIZATION. For now only "Basic" auth type is supported .. - -[2011-09-22] Javier - * NEW Example: added partial Restbuck example - -[2011-09-21] Jocelyn - * Nino connector: fixed an issue with missing value for Content-Type and Content-Length - -[2011-09-13] Jocelyn - * library "router": now using a generic design to allow customization of - request handler context class. - * NEW library "server/request/rest": first attempt to provide a library to - help building RESTful application (the interfaces are likely to change - soon) EXPERIMENTAL - -[2011-09-09] Jocelyn - * library "uri-template": better support for {/vars} and {?vars} - -[2011-09-07] Jocelyn - * library "router": now routing depends on uri (or uri template) and request methods - * Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable. - -[2011-09-07] Jocelyn - * changelog: starting to write down changelogs file +[Previous ] Many significant changes in v0 diff --git a/MIGRATION.md b/MIGRATION.md index 6b34d0b1..5a5b5bad 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,4 +1,4 @@ -Date: 2015-mar-31 +Date: 2015-june # Goal: ======= @@ -7,7 +7,7 @@ Date: 2015-mar-31 # Status: ========= -- The current version of EWF has mainly 3 connectors: CGI, libFCGI, and nino. +- The version v0 of EWF has mainly 3 connectors: CGI, libFCGI, and nino. - CGI and libFCGI connectors does not need any concurrency support. - But the nino connector had a pseudo concurrency support with Thread, however one could do write code that result in hasardeous concurrency execution. diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf index 83338d1e..2641135a 100644 --- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf +++ b/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf @@ -27,7 +27,6 @@ - /EIFGENs$ /concurrency$ /ssl$ /no_ssl$ From 0e3e97a7fd6c8a173b23b93560ae28627200febe Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 10 Jun 2015 16:49:23 +0200 Subject: [PATCH 02/36] Added a few example based on the obsolete libraries (v0). Updated the tutorial example. Added WSF_MESSAGE_EXECUTION. --- examples/obsolete/v0/filter/filter-safe.ecf | 35 ++ examples/obsolete/v0/filter/filter.rc | 6 + examples/obsolete/v0/filter/license.lic | 4 + examples/obsolete/v0/filter/readme.md | 4 + .../v0/filter/src/database/database_api.e | 57 ++ .../filter/src/database/shared_database_api.e | 20 + .../filter/src/domain/json_user_converter.e | 52 ++ examples/obsolete/v0/filter/src/domain/user.e | 59 ++ .../filter/src/filter/authentication_filter.e | 65 ++ .../src/filter/filter_handler_context.e | 34 ++ .../obsolete/v0/filter/src/filter_server.e | 111 ++++ .../v0/filter/src/resource/user_handler.e | 97 +++ .../v0/restbucksCRUD/README-compilation.txt | 3 + .../v0/restbucksCRUD/client/README.txt | 11 + .../v0/restbucksCRUD/client/client-safe.ecf | 19 + .../v0/restbucksCRUD/client/client.ecf | 19 + .../v0/restbucksCRUD/client/client.rc | 6 + .../client/src/restbuck_client.e | 154 +++++ .../obsolete/v0/restbucksCRUD/license.lic | 4 + examples/obsolete/v0/restbucksCRUD/readme.md | 297 +++++++++ examples/obsolete/v0/restbucksCRUD/readme.txt | 0 .../v0/restbucksCRUD/restbucks-safe.ecf | 55 ++ .../obsolete/v0/restbucksCRUD/restbucks.rc | 6 + .../restbucksCRUD/src/database/database_api.e | 26 + .../src/database/shared_database_api.e | 19 + .../v0/restbucksCRUD/src/domain/item.e | 90 +++ .../restbucksCRUD/src/domain/item_constants.e | 54 ++ .../src/domain/json_order_converter.e | 176 ++++++ .../v0/restbucksCRUD/src/domain/order.e | 114 ++++ .../src/domain/order_validation.e | 56 ++ .../src/domain/shared_order_validation.e | 19 + .../policy_driven_resource/order_handler.e | 574 ++++++++++++++++++ .../src/resource/order_handler.e | 403 ++++++++++++ .../v0/restbucksCRUD/src/restbucks_server.e | 58 ++ .../v0/restbucksCRUD/src/utils/etag_utils.e | 24 + examples/tutorial/README.wiki | 5 +- examples/tutorial/step_1.wiki | 4 +- examples/tutorial/step_2.wiki | 49 +- .../step_2/hello/alternatives/README.wiki | 6 +- .../alternatives/execute/hello_application.e | 39 -- .../execute/hello_with_execute.rc | 1 - .../alternatives/launcher/hello_application.e | 25 +- .../alternatives/launcher/hello_execution.e | 35 ++ .../alternatives/message/hello_application.e | 21 + .../alternatives/message/hello_execution.e | 27 + .../hello_with_execute.ecf | 3 +- examples/tutorial/step_2/hello/ewf.ini | 2 +- examples/tutorial/step_2/hello/hello.ecf | 4 +- .../hello/src/custom_hello_application.e | 21 +- .../step_2/hello/src/hello_application.e | 20 +- .../step_2/hello/src/hello_execution.e | 35 ++ examples/tutorial/step_3.wiki | 10 +- examples/tutorial/step_3/hello/hello.ecf | 2 +- .../step_3/hello/src/hello_application.e | 47 +- .../step_3/hello/src/hello_execution.e | 53 ++ examples/tutorial/step_4.wiki | 20 +- examples/tutorial/step_4/hello/hello.ecf | 2 +- .../step_4/hello/src/hello_application.e | 137 +---- .../step_4/hello/src/hello_execution.e | 135 ++++ .../src/image_uploader_execution.e | 2 +- .../consumer/demo/application_execution.e | 4 +- .../uri/helpers/wsf_routed_uri_helper.e | 16 + .../helpers/wsf_uri_response_agent_handler.e | 44 ++ .../helpers/wsf_routed_uri_template_helper.e | 36 +- library/server/wsf/router/wsf_router.e | 16 +- .../wsf/src/service/wsf_launchable_service.e | 10 + .../server/wsf/src/wsf_message_execution.e | 40 ++ tools/install_ewf.bat | 4 + 68 files changed, 3282 insertions(+), 324 deletions(-) create mode 100644 examples/obsolete/v0/filter/filter-safe.ecf create mode 100644 examples/obsolete/v0/filter/filter.rc create mode 100644 examples/obsolete/v0/filter/license.lic create mode 100644 examples/obsolete/v0/filter/readme.md create mode 100644 examples/obsolete/v0/filter/src/database/database_api.e create mode 100644 examples/obsolete/v0/filter/src/database/shared_database_api.e create mode 100644 examples/obsolete/v0/filter/src/domain/json_user_converter.e create mode 100644 examples/obsolete/v0/filter/src/domain/user.e create mode 100644 examples/obsolete/v0/filter/src/filter/authentication_filter.e create mode 100644 examples/obsolete/v0/filter/src/filter/filter_handler_context.e create mode 100644 examples/obsolete/v0/filter/src/filter_server.e create mode 100644 examples/obsolete/v0/filter/src/resource/user_handler.e create mode 100644 examples/obsolete/v0/restbucksCRUD/README-compilation.txt create mode 100644 examples/obsolete/v0/restbucksCRUD/client/README.txt create mode 100644 examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf create mode 100644 examples/obsolete/v0/restbucksCRUD/client/client.ecf create mode 100644 examples/obsolete/v0/restbucksCRUD/client/client.rc create mode 100644 examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e create mode 100644 examples/obsolete/v0/restbucksCRUD/license.lic create mode 100644 examples/obsolete/v0/restbucksCRUD/readme.md create mode 100644 examples/obsolete/v0/restbucksCRUD/readme.txt create mode 100644 examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf create mode 100644 examples/obsolete/v0/restbucksCRUD/restbucks.rc create mode 100644 examples/obsolete/v0/restbucksCRUD/src/database/database_api.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/database/shared_database_api.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/item.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/item_constants.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/json_order_converter.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/order.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/order_validation.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/domain/shared_order_validation.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/policy_driven_resource/order_handler.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e create mode 100644 examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e delete mode 100644 examples/tutorial/step_2/hello/alternatives/execute/hello_application.e delete mode 100644 examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.rc create mode 100644 examples/tutorial/step_2/hello/alternatives/launcher/hello_execution.e create mode 100644 examples/tutorial/step_2/hello/alternatives/message/hello_application.e create mode 100644 examples/tutorial/step_2/hello/alternatives/message/hello_execution.e rename examples/tutorial/step_2/hello/alternatives/{execute => message}/hello_with_execute.ecf (86%) create mode 100644 examples/tutorial/step_2/hello/src/hello_execution.e create mode 100644 examples/tutorial/step_3/hello/src/hello_execution.e create mode 100644 examples/tutorial/step_4/hello/src/hello_execution.e create mode 100644 library/server/wsf/router/support/uri/helpers/wsf_uri_response_agent_handler.e create mode 100644 library/server/wsf/src/wsf_message_execution.e diff --git a/examples/obsolete/v0/filter/filter-safe.ecf b/examples/obsolete/v0/filter/filter-safe.ecf new file mode 100644 index 00000000..8c6d4e4f --- /dev/null +++ b/examples/obsolete/v0/filter/filter-safe.ecf @@ -0,0 +1,35 @@ + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/obsolete/v0/filter/filter.rc b/examples/obsolete/v0/filter/filter.rc new file mode 100644 index 00000000..b0ec159c --- /dev/null +++ b/examples/obsolete/v0/filter/filter.rc @@ -0,0 +1,6 @@ +#include + +STRINGTABLE +BEGIN + 1 "This Program was made using EiffelStudio using Visual Studio C++" +END diff --git a/examples/obsolete/v0/filter/license.lic b/examples/obsolete/v0/filter/license.lic new file mode 100644 index 00000000..73a78070 --- /dev/null +++ b/examples/obsolete/v0/filter/license.lic @@ -0,0 +1,4 @@ +${NOTE_KEYWORD} + copyright: "2011-${YEAR}, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + diff --git a/examples/obsolete/v0/filter/readme.md b/examples/obsolete/v0/filter/readme.md new file mode 100644 index 00000000..b1a43c03 --- /dev/null +++ b/examples/obsolete/v0/filter/readme.md @@ -0,0 +1,4 @@ +Filter example + +To test the example, you can just run in a terminal: +> curl -u foo:bar http://localhost:9090/user/1 -v diff --git a/examples/obsolete/v0/filter/src/database/database_api.e b/examples/obsolete/v0/filter/src/database/database_api.e new file mode 100644 index 00000000..4c0024c0 --- /dev/null +++ b/examples/obsolete/v0/filter/src/database/database_api.e @@ -0,0 +1,57 @@ +note + description: "Summary description for {DATABASE_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DATABASE_API +create + make + +feature -- Initialization + + make + local + l_user: USER + do + create users.make (10) + create l_user.make (1, "foo", "bar") + users.put (l_user, l_user.id) + create l_user.make (2, "demo", "demo") + users.put (l_user, l_user.id) + end + +feature -- Access + + user (a_id: INTEGER; a_name: detachable READABLE_STRING_GENERAL): detachable USER + -- User with id `a_id' or name `a_name'. + require + a_id > 0 xor a_name /= Void + local + n: like {USER}.name + do + if a_id > 0 then + Result := users.item (a_id) + elseif a_name /= Void then + n := a_name.as_string_8 + across + users as c + until + Result /= Void + loop + if attached c.item as u and then u.name.same_string (n) then + Result := u + end + end + end + ensure + Result /= Void implies ((a_id > 0 and then Result.id = a_id) xor (a_name /= Void and then Result.name.same_string_general (a_name))) + end + + users: HASH_TABLE [USER, INTEGER] + +;note + copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/database/shared_database_api.e b/examples/obsolete/v0/filter/src/database/shared_database_api.e new file mode 100644 index 00000000..10ad5dff --- /dev/null +++ b/examples/obsolete/v0/filter/src/database/shared_database_api.e @@ -0,0 +1,20 @@ +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-2012, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/domain/json_user_converter.e b/examples/obsolete/v0/filter/src/domain/json_user_converter.e new file mode 100644 index 00000000..34800625 --- /dev/null +++ b/examples/obsolete/v0/filter/src/domain/json_user_converter.e @@ -0,0 +1,52 @@ +note + description: "JSON user converter." + author: "Olivier Ligot" + date: "$Date$" + revision: "$Revision$" + +class + JSON_USER_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + do + create object.make (0, "", "") + end + +feature -- Access + + object: USER + + value: detachable JSON_OBJECT + +feature -- Conversion + + from_json (j: attached like value): detachable like object + -- Convert from JSON value. + do + end + + to_json (o: like object): like value + -- Convert to JSON value. + do + create Result.make + Result.put (json.value (o.id), id_key) + Result.put (json.value (o.name), name_key) + end + + feature {NONE} -- Implementation + + id_key: STRING = "id" + name_key: STRING = "name" + +note + copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/domain/user.e b/examples/obsolete/v0/filter/src/domain/user.e new file mode 100644 index 00000000..0ad70f2c --- /dev/null +++ b/examples/obsolete/v0/filter/src/domain/user.e @@ -0,0 +1,59 @@ +note + description: "User." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + USER + +inherit + ANY + redefine + is_equal + end + +create + make + +feature {NONE} -- Initialization + + make (an_id: INTEGER; a_name, a_password: STRING) + do + id := an_id + name := a_name + password := a_password + ensure + id_set: id = an_id + name_set: name = a_name + password_set: password = a_password + end + +feature -- Access + + id: INTEGER + -- Identifier + + name: STRING + -- Name + + password: STRING + -- Password + +feature -- Comparison + + is_equal (other: like Current): BOOLEAN + -- Is `other' attached to an object considered + -- equal to current object? + do + if Current = other then + Result := True + else + Result := (id = other.id) and (name = other.name) and (password = other.password) + end + end + +;note + copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/filter/authentication_filter.e b/examples/obsolete/v0/filter/src/filter/authentication_filter.e new file mode 100644 index 00000000..c3bf8ae3 --- /dev/null +++ b/examples/obsolete/v0/filter/src/filter/authentication_filter.e @@ -0,0 +1,65 @@ +note + description: "Authentication filter." + author: "Olivier Ligot" + date: "$Date$" + revision: "$Revision$" + +class + AUTHENTICATION_FILTER + +inherit + WSF_FILTER + + WSF_URI_TEMPLATE_HANDLER + + SHARED_DATABASE_API + + SHARED_EJSON + +feature -- Basic operations + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute the filter + local + l_auth: detachable HTTP_AUTHORIZATION + do + if attached req.http_authorization as l_http_authorization then + create l_auth.make (l_http_authorization) + end + if + l_auth /= Void and then + l_auth.is_basic and then + attached l_auth.login as l_auth_login and then + attached Db_access.user (0, l_auth_login) as l_user and then + l_auth_login.same_string (l_user.name) and then + attached l_auth.password as l_auth_password and then + l_auth_password.same_string (l_user.password) + then + req.set_execution_variable ("user", l_user) + execute_next (req, res) + else + handle_unauthorized ("Unauthorized", req, res) + end + end + +feature {NONE} -- Implementation + + handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE) + -- Handle forbidden. + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_plain + h.put_content_length (a_description.count) + h.put_current_date + h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"User%"") + res.set_status_code ({HTTP_STATUS_CODE}.unauthorized) + res.put_header_text (h.string) + res.put_string (a_description) + end + +note + copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/filter/filter_handler_context.e b/examples/obsolete/v0/filter/src/filter/filter_handler_context.e new file mode 100644 index 00000000..a4f5a448 --- /dev/null +++ b/examples/obsolete/v0/filter/src/filter/filter_handler_context.e @@ -0,0 +1,34 @@ +note + description: "Summary description for {FILTER_HANDLER_CONTEXT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + FILTER_HANDLER_CONTEXT + +inherit + WSF_HANDLER_CONTEXT + +create + make + +feature -- Access + + user: detachable USER + -- Authenticated user + +feature -- Element change + + set_user (a_user: USER) + -- Set `user' to `a_user' + do + user := a_user + ensure + user_set: user = a_user + end + +note + copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/filter/src/filter_server.e b/examples/obsolete/v0/filter/src/filter_server.e new file mode 100644 index 00000000..dfc9f8fe --- /dev/null +++ b/examples/obsolete/v0/filter/src/filter_server.e @@ -0,0 +1,111 @@ +note + description : "Filter example." + author : "Olivier Ligot" + date : "$Date$" + revision : "$Revision$" + +class + FILTER_SERVER + +inherit + ANY + + WSF_DEFAULT_SERVICE + + WSF_ROUTED_SERVICE + undefine + execute + end + + WSF_FILTERED_SERVICE + + SHARED_EJSON + +create + make + +feature {NONE} -- Initialization + + make + local + l_message: STRING + l_factory: INET_ADDRESS_FACTORY + do + initialize_router + initialize_filter + initialize_json + set_service_option ("port", port) + create l_message.make_empty + l_message.append_string ("Launching filter server at ") + create l_factory + l_message.append_string (l_factory.create_localhost.host_name) + l_message.append_string (" port ") + l_message.append_integer (port) + io.put_string (l_message) + io.put_new_line + make_and_launch + end + + create_filter + -- Create `filter' + do + create {WSF_CORS_FILTER} filter + end + + setup_filter + -- Setup `filter' + local + l_routing_filter: WSF_ROUTING_FILTER + l_logging_filter: WSF_LOGGING_FILTER + do + create l_routing_filter.make (router) + l_routing_filter.set_execute_default_action (agent execute_default) + filter.set_next (l_routing_filter) + + create l_logging_filter + l_routing_filter.set_next (l_logging_filter) + end + + setup_router + -- Setup `router' + local + l_options_filter: WSF_CORS_OPTIONS_FILTER + l_authentication_filter: AUTHENTICATION_FILTER + l_user_filter: USER_HANDLER + l_methods: WSF_REQUEST_METHODS + do + create l_options_filter.make (router) + create l_authentication_filter + create l_user_filter + + l_options_filter.set_next (l_authentication_filter) + l_authentication_filter.set_next (l_user_filter) + + create l_methods + l_methods.enable_options + l_methods.enable_get + router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods) + end + + initialize_json + -- Initialize `json'. + do + json.add_converter (create {JSON_USER_CONVERTER}.make) + end + +feature {NONE} -- Implementation + + port: INTEGER = 9090 + -- Port number + +note + copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat 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/obsolete/v0/filter/src/resource/user_handler.e b/examples/obsolete/v0/filter/src/resource/user_handler.e new file mode 100644 index 00000000..722ccd03 --- /dev/null +++ b/examples/obsolete/v0/filter/src/resource/user_handler.e @@ -0,0 +1,97 @@ +note + description: "User handler." + author: "Olivier Ligot" + date: "$Date$" + revision: "$Revision$" + +class + USER_HANDLER + +inherit + WSF_FILTER + + WSF_URI_TEMPLATE_HANDLER + + WSF_RESOURCE_HANDLER_HELPER + redefine + do_get + end + + SHARED_DATABASE_API + + SHARED_EJSON + +feature -- Basic operations + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute_methods (req, res) + execute_next (req, res) + end + + do_get (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 user + -- If the GET request is not SUCCESS, we response with + -- 404 Resource not found + require else + authenticated_user_attached: attached {USER} req.execution_variable ("user") + local + id : STRING + do + if attached req.orig_path_info as orig_path then + id := get_user_id_from_path (orig_path) + if attached retrieve_user (id) as l_user then + if l_user ~ req.execution_variable ("user") then + compute_response_get (req, res, l_user) + elseif attached {USER} req.execution_variable ("user") as l_auth_user then + -- Trying to access another user that the authenticated one, + -- which is forbidden in this example... + handle_forbidden ("You try to access the user " + id.out + " while authenticating with the user " + l_auth_user.id.out, req, res) + end + else + handle_resource_not_found_response ("The following resource " + orig_path + " is not found ", req, res) + end + end + end + +feature {NONE} -- Implementation + + compute_response_get (req: WSF_REQUEST; res: WSF_RESPONSE; l_user : USER) + local + h: HTTP_HEADER + l_msg : STRING + do + create h.make + h.put_content_type_application_json + if attached {JSON_VALUE} json.value (l_user) as jv then + l_msg := jv.representation + h.put_content_length (l_msg.count) + if attached req.request_time as time then + h.put_utc_date (time) + end + res.set_status_code ({HTTP_STATUS_CODE}.ok) + res.put_header_text (h.string) + res.put_string (l_msg) + end + end + + get_user_id_from_path (a_path: READABLE_STRING_32): STRING + do + Result := a_path.split ('/').at (3) + end + + retrieve_user (id: STRING) : detachable USER + -- Retrieve the user by id if it exist, in other case, Void + do + if id.is_integer and then Db_access.users.has (id.to_integer) then + Result := db_access.users.item (id.to_integer) + end + end + +note + copyright: "2011-2013, Olivier Ligot, Jocelyn Fiat and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/README-compilation.txt b/examples/obsolete/v0/restbucksCRUD/README-compilation.txt new file mode 100644 index 00000000..6e3dfa50 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/README-compilation.txt @@ -0,0 +1,3 @@ +The current example has a main target for the server: "restbucks" +But we also provide "policy_driven_restbucks" target which is using the +policy-driven framework than help coder fulfill HTTP expectations. diff --git a/examples/obsolete/v0/restbucksCRUD/client/README.txt b/examples/obsolete/v0/restbucksCRUD/client/README.txt new file mode 100644 index 00000000..033eaaf4 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/client/README.txt @@ -0,0 +1,11 @@ +Make sure to have the Clib generated in the related cURL library + +- if you use EiffelStudio >= 7.0 + check %ISE_LIBRARY%\library\cURL\spec\%ISE_C_COMPILER%\$ISE_PLATFORM + or $ISE_LIBRARY/library/cURL/spec/$ISE_PLATFORM + +- otherwise if you use earlier version + check under ext/ise_library/curl/spec/... + +And on Windows, be sure to get the libcurl.dll from %ISE_LIBRARY%\studio\spec\%ISE_PLATFORM%\bin\libcurl.dll + diff --git a/examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf b/examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf new file mode 100644 index 00000000..d987ddaa --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/client/client-safe.ecf @@ -0,0 +1,19 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + diff --git a/examples/obsolete/v0/restbucksCRUD/client/client.ecf b/examples/obsolete/v0/restbucksCRUD/client/client.ecf new file mode 100644 index 00000000..086d5727 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/client/client.ecf @@ -0,0 +1,19 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + diff --git a/examples/obsolete/v0/restbucksCRUD/client/client.rc b/examples/obsolete/v0/restbucksCRUD/client/client.rc new file mode 100644 index 00000000..b0ec159c --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/client/client.rc @@ -0,0 +1,6 @@ +#include + +STRINGTABLE +BEGIN + 1 "This Program was made using EiffelStudio using Visual Studio C++" +END diff --git a/examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e b/examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e new file mode 100644 index 00000000..56a82390 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/client/src/restbuck_client.e @@ -0,0 +1,154 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + RESTBUCK_CLIENT + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + local + h: LIBCURL_HTTP_CLIENT + sess: HTTP_CLIENT_SESSION + resp : detachable HTTP_CLIENT_RESPONSE + l_location : detachable READABLE_STRING_8 + body : STRING + do + create h.make + sess := h.new_session ("http://127.0.0.1:9090") +-- Uncomment the following 2 lines, if you use fiddler2 web debugging tool +-- sess.set_is_debug (True) +-- sess.set_proxy ("127.0.0.1", 8888) + + -- Create Order + print ("%N Create Order %N") + resp := create_order (sess) + + + -- Read the Order + print ("%N Read Order %N") + l_location := resp.header ("Location") + resp := read_order (sess, l_location) + + + -- Update the Order + if resp /= Void and then attached resp.body as l_body then + body := l_body.as_string_8 + body.replace_substring_all ("takeAway", "in Shop") + print ("%N Update Order %N") + resp := update_order (sess, l_location, body) + end + end + + update_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8; a_body : STRING): detachable HTTP_CLIENT_RESPONSE + local + context : HTTP_CLIENT_REQUEST_CONTEXT + do + if attached uri as l_uri then + sess.set_base_url (l_uri) + create context.make + context.headers.put ("application/json", "Content-Type") + Result := sess.put ("", context, a_body ) + -- Show headers + across + Result.headers as l_headers + loop + print (l_headers.item.name) + print (":") + print (l_headers.item.value) + io.put_new_line + end + + -- Show body + print (Result.body) + io.put_new_line + end + end + + + read_order ( sess: HTTP_CLIENT_SESSION; uri : detachable READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + if attached uri as l_uri then + sess.set_base_url (l_uri) + Result := sess.get ("", Void) + -- Show headers + across + Result.headers as l_headers + loop + print (l_headers.item.name) + print (":") + print (l_headers.item.value) + io.put_new_line + end + + -- Show body + print (Result.body) + io.put_new_line + end + end + + + + create_order (sess: HTTP_CLIENT_SESSION) : HTTP_CLIENT_RESPONSE + local + s: READABLE_STRING_8 + j: JSON_PARSER + id: detachable STRING + context : HTTP_CLIENT_REQUEST_CONTEXT + do + s := "[ + { + "location":"takeAway", + "items":[ + { + "name":"Late", + "option":"skim", + "size":"Small", + "quantity":1 + } + ] + } + ]" + + create context.make + context.headers.put ("application/json", "Content-Type") + Result := sess.post ("/order", context, s) + -- Show the Headers + across + Result.headers as l_headers + loop + print (l_headers.item.name) + print (":") + print (l_headers.item.value) + io.put_new_line + end + + + -- Show the Response body + if attached Result.body as m then + create j.make_with_string (m) + j.parse_content + if j.is_valid and then attached j.parsed_json_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 + + +feature {NONE} -- Implementation + +invariant +-- invariant_clause: True + +end diff --git a/examples/obsolete/v0/restbucksCRUD/license.lic b/examples/obsolete/v0/restbucksCRUD/license.lic new file mode 100644 index 00000000..6928e20b --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/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/obsolete/v0/restbucksCRUD/readme.md b/examples/obsolete/v0/restbucksCRUD/readme.md new file mode 100644 index 00000000..6b85f132 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/readme.md @@ -0,0 +1,297 @@ +Restbuck Eiffel Implementation based on the book of REST in Practice +==================================================================== +This is an implementation of CRUD pattern for manipulate resources, this is the first step to use +the HTTP protocol as an application protocol instead of a transport protocol. + +Restbuck Protocol +----------------- + + + + + + + +
Verb URI or template Use
POST /order Create a new order, and upon success, receive a Locationheader specifying the new order's URI.
GET /order/{orderId} Request the current state of the order specified by the URI.
PUT /order/{orderId} Update an order at the given URI with new information, providing the full representation.
DELETE /order/{orderId} Logically remove the order identified by the given URI.
+ +Resource Represenation +---------------------- +The previous tables shows a contrat, the URI or URI template, allows us to indentify resources, now we will chose a +representacion, for this particular case we will use JSON. + +Note:
+1. *A resource can have multiple URIs*.
+2. *A resource can have multiple Representations*.
+ +RESTBUCKS_SERVER +---------------- +This class implement the main entry of our REST CRUD service, we are using a default connector (Nino Connector, +using a WebServer written in Eiffel). +We are inheriting from URI_TEMPLATE_ROUTED_SERVICE, this allows us to map our service contrat, as is shown in the previous +table, the mapping is defined in the feature setup_router, this also show that the class ORDER_HANDLER will be encharge +of to handle different type of request to the ORDER resource. + + + class + RESTBUCKS_SERVER + + inherit + ANY + + URI_TEMPLATE_ROUTED_SERVICE + + DEFAULT_SERVICE + -- Here we are using a default connector using the default Nino Connector, + -- but it's possible to use other connector (CGI or FCGI). + + create + make + + feature {NONE} -- Initialization + + make + -- Initialize the router (this will have the request handler and + -- their context). + do + initialize_router + make_and_launch + 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 + + end + + + +How to Create an order with POST +-------------------------------- + +Here is the convention that we are using: +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 +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 +400 BAD REQUEST, the client send a bad request or +500 INTERNAL_SERVER_ERROR, when the server can deliver the request. + + POST /order HTTP/1.1 + Host: 127.0.0.1:8080 + Connection: keep-alive + Content-Length: 196 + Origin: chrome-extension://fhjcajmcbmldlhcimfajhfbgofnpcjmb + Content-Type: application/json + Accept: */* + Accept-Encoding: gzip,deflate,sdch + Accept-Language: es-419,es;q=0.8,en;q=0.6 + Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 + + { + "location":"takeAway", + "items":[ + { + "name":"Late", + "option":"skim", + "size":"Small", + "quantity":1 + } + ] + } + +Response success + + HTTP/1.1 201 Created + Status 201 Created + Content-Type application/json + Content-Length 123 + Location http://localhost:8080/order/1 + Date FRI,09 DEC 2011 20:34:20.00 GMT + + { + "location" : "takeAway", + "status" : "submitted", + "items" : [ { + "name" : "late", + "size" : "small", + "quantity" : 1, + "option" : "skim" + } ] + } + +note: + curl -vv http://localhost:9090/order -H "Content-Type: application/json" -d "{\"location\":\"takeAway\",\"items\":[{\"name\":\"Late\",\"option\":\"skim\",\"size\":\"Small\",\"quantity\":1}]}" -X POST + + +How to Read an order with GET +----------------------------- +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 Conditional GET and the resource does not change we send a 304, Resource not modifed + + GET /order/1 HTTP/1.1 + Host: 127.0.0.1:8080 + Connection: keep-alive + Accept: */* + Accept-Encoding: gzip,deflate,sdch + Accept-Language: es-419,es;q=0.8,en;q=0.6 + Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 + If-None-Match: 6542EF270D91D3EAF39CFB382E4CEBA7 + +Response + HTTP/1.1 200 OK + + Status 200 OK + Content-Type application/json + Content-Length 123 + Date FRI,09 DEC 2011 20:53:46.00 GMT + etag 2ED3A40954A95D766FC155682DC8BB52 + + { + "location" : "takeAway", + "status" : "submitted", + "items" : [ { + "name" : "late", + "size" : "small", + "quantity" : 1, + "option" : "skim" + } ] + } + +note: + curl -vv http://localhost:9090/order/1 + +How to Update an order 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. + +Suposse that we had created an Order with the values shown in the _How to create an order with POST_ +But we change our decision and we want to stay in the shop. + + + + PUT /order/1 HTTP/1.1 + Content-Length: 122 + Content-Type: application/json; charset=UTF-8 + Host: localhost:8080 + Connection: Keep-Alive + Expect: 100-Continue + + { + "location" : "in shop", + "status" : "submitted", + "items" : [ { + "name" : "late", + "size" : "small", + "quantity" : 1, + "option" : "skim" + } ] + } + + +Response success + + HTTP/1.1 200 OK + Status 200 OK + Content-Type application/json + Date FRI,09 DEC 2011 21:06:26.00 GMT + etag 8767F900674B843E1F3F70BCF3E62403 + Content-Length 122 + + { + "location" : "in shop", + "status" : "submitted", + "items" : [ { + "name" : "late", + "size" : "small", + "quantity" : 1, + "option" : "skim" + } ] + } + +How to Delete an order with DELETE +---------------------------------- +Here we use DELETE to cancel an order, if that order is in state where it can still be canceled. +204 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 + + + DELETE /order/1 HTTP/1.1 + Host: localhost:8080 + Connection: Keep-Alive + +Response success + + HTTP/1.1 204 No Content + + Status 204 No Content + Content-Type application/json + Date FRI,09 DEC 2011 21:10:51.00 GMT + +If we want to check that the resource does not exist anymore we can try to retrieve a GET /order/1 and we will receive a +404 No Found + + GET /order/1 HTTP/1.1 + Host: localhost:8080 + Connection: Keep-Alive + +Response + + HTTP/1.1 404 Not Found + + Status 404 Not Found + Content-Type application/json + Content-Length 44 + Date FRI,09 DEC 2011 21:14:17.79 GMT + + The following resource/order/1 is not found + + +References +---------- +1. [How to get a cup of coffe](http://www.infoq.com/articles/webber-rest-workflow) +2. [Rest in Practice] (http://restinpractice.com/default.aspx) diff --git a/examples/obsolete/v0/restbucksCRUD/readme.txt b/examples/obsolete/v0/restbucksCRUD/readme.txt new file mode 100644 index 00000000..e69de29b diff --git a/examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf b/examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf new file mode 100644 index 00000000..ca3978b8 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/restbucks-safe.ecf @@ -0,0 +1,55 @@ + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + + + + + + + + + /policy_driven_resource$ + + + + + + + + + + /resource$ + + + + diff --git a/examples/obsolete/v0/restbucksCRUD/restbucks.rc b/examples/obsolete/v0/restbucksCRUD/restbucks.rc new file mode 100644 index 00000000..b0ec159c --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/restbucks.rc @@ -0,0 +1,6 @@ +#include + +STRINGTABLE +BEGIN + 1 "This Program was made using EiffelStudio using Visual Studio C++" +END diff --git a/examples/obsolete/v0/restbucksCRUD/src/database/database_api.e b/examples/obsolete/v0/restbucksCRUD/src/database/database_api.e new file mode 100644 index 00000000..efc0bf20 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/database/database_api.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/database/shared_database_api.e b/examples/obsolete/v0/restbucksCRUD/src/database/shared_database_api.e new file mode 100644 index 00000000..de4c9a22 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/database/shared_database_api.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/item.e b/examples/obsolete/v0/restbucksCRUD/src/domain/item.e new file mode 100644 index 00000000..2e27cf5a --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/item.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/item_constants.e b/examples/obsolete/v0/restbucksCRUD/src/domain/item_constants.e new file mode 100644 index 00000000..ecea445d --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/item_constants.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/json_order_converter.e b/examples/obsolete/v0/restbucksCRUD/src/domain/json_order_converter.e new file mode 100644 index 00000000..1d022062 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/json_order_converter.e @@ -0,0 +1,176 @@ +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 + + if attached {STRING_32} json.object (j.item (id_key), Void) as l_id then + s_id := s_id + end + if attached {STRING_32} json.object (j.item (location_key), Void) as l_location then + s_location := l_location + end + if attached {STRING_32} json.object (j.item (status_key), Void) as l_status then + s_status := l_status + end + + 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_empty + 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_from_string ("id") + end + + location_key: JSON_STRING + once + create Result.make_from_string ("location") + end + + status_key: JSON_STRING + once + create Result.make_from_string ("status") + end + + items_key : JSON_STRING + once + create Result.make_from_string ("items") + end + + + name_key : JSON_STRING + + once + create Result.make_from_string ("name") + end + + size_key : JSON_STRING + + once + create Result.make_from_string ("size") + end + + quantity_key : JSON_STRING + + once + create Result.make_from_string ("quantity") + end + + + option_key : JSON_STRING + + once + create Result.make_from_string ("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-2015, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/order.e b/examples/obsolete/v0/restbucksCRUD/src/domain/order.e new file mode 100644 index 00000000..721d2256 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/order.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/order_validation.e b/examples/obsolete/v0/restbucksCRUD/src/domain/order_validation.e new file mode 100644 index 00000000..5583a318 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/order_validation.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/domain/shared_order_validation.e b/examples/obsolete/v0/restbucksCRUD/src/domain/shared_order_validation.e new file mode 100644 index 00000000..4e3a1d33 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/domain/shared_order_validation.e @@ -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-2012, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/policy_driven_resource/order_handler.e b/examples/obsolete/v0/restbucksCRUD/src/policy_driven_resource/order_handler.e new file mode 100644 index 00000000..31410477 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/policy_driven_resource/order_handler.e @@ -0,0 +1,574 @@ +note + description: "{ORDER_HANDLER} handle the resources that we want to expose" + author: "" + date: "$Date$" + revision: "$Revision$" + +class ORDER_HANDLER + +inherit + + WSF_SKELETON_HANDLER + + SHARED_DATABASE_API + + SHARED_EJSON + + REFACTORING_HELPER + + SHARED_ORDER_VALIDATION + + WSF_RESOURCE_HANDLER_HELPER + rename + execute_options as helper_execute_options, + handle_internal_server_error as helper_handle_internal_server_error + end + +create + + make_with_router + + +feature -- Execution variables + + Order_execution_variable: STRING = "ORDER" + -- Execution variable used by application + + Generated_content_execution_variable: STRING = "GENERATED_CONTENT" + -- Execution variable used by application + + Extracted_order_execution_variable: STRING = "EXTRACTED_ORDER" + -- Execution variable used by application + +feature -- Documentation + + description: READABLE_STRING_GENERAL + -- General description for self-generated documentation; + -- The specific URI templates supported will be described automatically + do + Result := "Create, Read, Update or Delete an ORDER." + end + +feature -- Access + + is_chunking (req: WSF_REQUEST): BOOLEAN + -- Will the response to `req' using chunked transfer encoding? + do + -- No. + end + + includes_response_entity (req: WSF_REQUEST): BOOLEAN + -- Does the response to `req' include an entity? + -- Method will be DELETE, POST, PUT or an extension method. + do + Result := False + -- At present, there is no support for this except for DELETE. + end + + conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION + -- Content negotiatior for all requests + once + create Result.make ({HTTP_MIME_TYPES}.application_json, "en", "UTF-8", "identity") + end + + mime_types_supported (req: WSF_REQUEST): LIST [STRING] + -- All values for Accept header that `Current' can serve + do + create {ARRAYED_LIST [STRING]} Result.make_from_array (<<{HTTP_MIME_TYPES}.application_json>>) + Result.compare_objects + end + + languages_supported (req: WSF_REQUEST): LIST [STRING] + -- All values for Accept-Language header that `Current' can serve + do + create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"en">>) + Result.compare_objects + end + + charsets_supported (req: WSF_REQUEST): LIST [STRING] + -- All values for Accept-Charset header that `Current' can serve + do + create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"UTF-8">>) + Result.compare_objects + end + + encodings_supported (req: WSF_REQUEST): LIST [STRING] + -- All values for Accept-Encoding header that `Current' can serve + do + create {ARRAYED_LIST [STRING]} Result.make_from_array (<<"identity">>) + Result.compare_objects + end + + max_age (req: WSF_REQUEST): NATURAL + -- Maximum age in seconds before response to `req` is considered stale; + -- This is used to generate a Cache-Control: max-age header. + -- Return 0 to indicate already expired. + -- Return Never_expires to indicate never expires. + do + -- All our responses are considered stale. + end + + is_freely_cacheable (req: WSF_REQUEST): BOOLEAN + -- Should the response to `req' be freely cachable in shared caches? + -- If `True', then a Cache-Control: public header will be generated. + do + -- definitely not! + end + + private_headers (req: WSF_REQUEST): detachable LIST [READABLE_STRING_8] + -- Header names intended for a single user. + -- If non-Void, then a Cache-Control: private header will be generated. + -- Returning an empty list prevents the entire response from being served from a shared cache. + do + create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (0) + end + + non_cacheable_headers (req: WSF_REQUEST): detachable LIST [READABLE_STRING_8] + -- Header names that will not be sent from a cache without revalidation; + -- If non-Void, then a Cache-Control: no-cache header will be generated. + -- Returning an empty list prevents the response being served from a cache + -- without revalidation. + do + create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (0) + end + + is_sensitive (req: WSF_REQUEST): BOOLEAN + -- Is the response to `req' of a sensitive nature? + -- If `True' then a Cache-Control: no-store header will be generated. + do + Result := True + -- since it's commercial data. + end + + allowed_cross_origins (req: WSF_REQUEST): detachable STRING + -- Value for Access-Control-Allow-Origin header; + -- If supplied, should be a single URI, or the values "*" or "null". + -- This is currently supported only for GET requests, and POSTs that functions as GET. + do + if req.is_get_head_request_method then + Result := "*" + end + end + + matching_etag (req: WSF_REQUEST; a_etag: READABLE_STRING_32; a_strong: BOOLEAN): BOOLEAN + -- Is `a_etag' a match for resource requested in `req'? + -- If `a_strong' then the strong comparison function must be used. + local + l_id: STRING + l_etag_util: ETAG_UTILS + do + l_id := order_id_from_request (req) + if db_access.orders.has_key (l_id) then + check attached db_access.orders.item (l_id) as l_order then + -- postcondition of `has_key' + create l_etag_util + Result := a_etag.same_string (l_etag_util.md5_digest (l_order.out).as_string_32) + end + end + end + + etag (req: WSF_REQUEST): detachable READABLE_STRING_8 + -- Optional Etag for `req' in the requested variant + local + l_etag_utils: ETAG_UTILS + do + create l_etag_utils + if attached {ORDER} req.execution_variable (Order_execution_variable) as l_order then + Result := l_etag_utils.md5_digest (l_order.out) + end + end + + last_modified (req: WSF_REQUEST): detachable DATE_TIME + -- When representation of resource selected in `req' was last modified; + -- SHOULD be set whenever it can reasonably be determined. + do + end + + modified_since (req: WSF_REQUEST; a_date_time: DATE_TIME): BOOLEAN + -- Has resource requested in `req' been modified since `a_date_time' (UTC)? + do + -- We don't track this information. It is safe to always say yes. + Result := True + end + +feature -- Measurement + + content_length (req: WSF_REQUEST): NATURAL + -- Length of entity-body of the response to `req' + do + check attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable) as l_response then + -- postcondition generated_content_set_for_get_head of `ensure_content_available' + -- We only call this for GET/HEAD in this example. + Result := l_response.count.as_natural_32 + end + end + + allow_post_to_missing_resource (req: WSF_REQUEST): BOOLEAN + -- The resource named in `req' does not exist, and this is a POST. Do we allow it? + do + -- No. + end + +feature -- Status report + + finished (req: WSF_REQUEST): BOOLEAN + -- Has the last chunk been generated for `req'? + do + -- precondition is never met + end + +feature -- Execution + + check_resource_exists (req: WSF_REQUEST; a_helper: WSF_METHOD_HELPER) + -- Call `a_helper.set_resource_exists' to indicate that `req.path_translated' + -- is the name of an existing resource. + -- We also put the order into `req.execution_variable (Order_execution_variable)' for GET or HEAD responses. + local + l_id: STRING + do + if req.is_post_request_method then + a_helper.set_resource_exists + -- because only /order is defined to this handler for POST + else + -- the request is of the form /order/{orderid} + l_id := order_id_from_request (req) + if db_access.orders.has_key (l_id) then + a_helper.set_resource_exists + if req.is_get_head_request_method then + check attached db_access.orders.item (l_id) as l_order then + -- postcondition `item_if_found' of `has_key' + req.set_execution_variable (Order_execution_variable, l_order) + end + end + end + end + ensure then + order_saved_only_for_get_head: attached {ORDER} req.execution_variable (Order_execution_variable) implies req.is_get_head_request_method + end + +feature -- GET/HEAD content + + ensure_content_available (req: WSF_REQUEST) + -- Commence generation of response text (entity-body). + -- If not chunked, then this will create the entire entity-body so as to be available + -- for a subsequent call to `content'. + -- If chunked, only the first chunk will be made available to `next_chunk'. If chunk extensions + -- are used, then this will also generate the chunk extension for the first chunk. + -- We save the text in `req.execution_variable (Generated_content_execution_variable)' + -- We ignore the results of content negotiation, as there is only one possible combination. + do + check attached {ORDER} req.execution_variable (Order_execution_variable) as l_order then + -- precondition get_or_head and postcondition order_saved_only_for_get_head of `check_resource_exists' and + if attached {JSON_VALUE} json.value (l_order) as jv then + req.set_execution_variable (Generated_content_execution_variable, jv.representation) + else + req.set_execution_variable (Generated_content_execution_variable, "") + end + end + ensure then + generated_content_set_for_get_head: req.is_get_head_request_method implies + attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable) + end + + content (req: WSF_REQUEST): READABLE_STRING_8 + -- Non-chunked entity body in response to `req'; + -- We only call this for GET/HEAD in this example. + do + check attached {READABLE_STRING_8} req.execution_variable (Generated_content_execution_variable) as l_response then + -- postcondition generated_content_set_for_get_head of `ensure_content_available' + Result := l_response + end + end + + next_chunk (req: WSF_REQUEST): TUPLE [a_chunk: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] + -- Next chunk of entity body in response to `req'; + -- The second field of the result is an optional chunk extension. + do + -- precondition `is_chunking' is never met, but we need a dummy `Result' + -- to satisfy the compiler in void-safe mode + Result := ["", Void] + end + + generate_next_chunk (req: WSF_REQUEST) + -- Prepare next chunk (including optional chunk extension) of entity body in response to `req'. + -- This is not called for the first chunk. + do + -- precondition `is_chunking' is never met + end + +feature -- DELETE + + delete (req: WSF_REQUEST) + -- Delete resource named in `req' or set an error on `req.error_handler'. + local + l_id: STRING + do + l_id := order_id_from_request (req) + if db_access.orders.has_key (l_id) then + if is_valid_to_delete (l_id) then + delete_order (l_id) + else + req.error_handler.add_custom_error ({HTTP_STATUS_CODE}.method_not_allowed, "DELETE not valid", + "There is conflict while trying to delete the order, the order could not be deleted in the current state") + end + else + req.error_handler.add_custom_error ({HTTP_STATUS_CODE}.not_found, "DELETE not valid", + "There is no such order to delete") + end + end + + delete_queued (req: WSF_REQUEST): BOOLEAN + -- Has resource named by `req' been queued for deletion? + do + -- No + end + + +feature -- PUT/POST + + is_entity_too_large (req: WSF_REQUEST): BOOLEAN + -- Is the entity stored in `req.execution_variable (Request_entity_execution_variable)' too large for the application? + do + -- No. We don't care for this example. + end + + check_content_headers (req: WSF_REQUEST) + -- Check we can support all content headers on request entity. + -- Set `req.execution_variable (Content_check_code_execution_variable)' to {NATURAL} zero if OK, or 415 or 501 if not. + do + -- We don't bother for this example. Note that this is equivalent to setting zero. + end + + create_resource (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Create new resource in response to a PUT request when `check_resource_exists' returns `False'. + -- Implementor must set error code of 200 OK or 500 Server Error. + do + -- We don't support creating a new resource with PUT. But this can't happen + -- with our router mappings, so we don't bother to set a 500 response. + end + + append_resource (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Create new resource in response to a POST request. + -- Implementor must set error code of 200 OK or 204 No Content or 303 See Other or 500 Server Error. + do + if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then + save_order (l_order) + compute_response_post (req, res, l_order) + else + handle_bad_request_response ("Not a valid order", req, res) + end + end + + check_conflict (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Check we can support all content headers on request entity. + -- Set `req.execution_variable (Conflict_check_code_execution_variable)' to {NATURAL} zero if OK, or 409 if not. + -- In the latter case, write the full error response to `res'. + do + if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then + if not is_valid_to_update (l_order) then + req.set_execution_variable (Conflict_check_code_execution_variable, {NATURAL} 409) + handle_resource_conflict_response (l_order.out +"%N There is conflict while trying to update the order, the order could not be update in the current state", req, res) + end + else + req.set_execution_variable (Conflict_check_code_execution_variable, {NATURAL} 409) + --| This ought to be a 500, as if attached should probably be check attached. But as yet I lack a proof. + handle_resource_conflict_response ("There is conflict while trying to update the order, the order could not be update in the current state", req, res) + end + end + + check_request (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Check that the request entity is a valid request. + -- The entity is available as `req.execution_variable (Conflict_check_code_execution_variable)'. + -- Set `req.execution_variable (Request_check_code_execution_variable)' to {NATURAL} zero if OK, or 400 if not. + -- In the latter case, write the full error response to `res'. + local + l_order: detachable ORDER + l_id: STRING + do + if attached {READABLE_STRING_8} req.execution_variable (Request_entity_execution_variable) as l_request then + l_order := extract_order_request (l_request) + if req.is_put_request_method then + l_id := order_id_from_request (req) + if l_order /= Void and then db_access.orders.has_key (l_id) then + l_order.set_id (l_id) + req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 0) + req.set_execution_variable (Extracted_order_execution_variable, l_order) + else + req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 400) + handle_bad_request_response (l_request +"%N is not a valid ORDER, maybe the order does not exist in the system", req, res) + end + else + req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 0) + req.set_execution_variable (Extracted_order_execution_variable, l_order) + end + else + req.set_execution_variable (Request_check_code_execution_variable, {NATURAL} 400) + handle_bad_request_response ("Request is not a valid ORDER", req, res) + end + end + + update_resource (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Perform the update requested in `req'. + -- Write a response to `res' with a code of 204 or 500. + do + if attached {ORDER} req.execution_variable (Extracted_order_execution_variable) as l_order then + update_order (l_order) + compute_response_put (req, res, l_order) + else + handle_internal_server_error (res) + end + end + +feature -- HTTP Methods + + compute_response_put (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_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.put_header_text (h.string) + res.put_string (jv.representation) + end + end + + compute_response_post (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_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.put_header_text (h.string) + res.put_string (l_msg) + end + end + +feature {NONE} -- URI helper methods + + order_id_from_request (req: WSF_REQUEST): STRING + -- Value of "orderid" template URI variable in `req' + require + req_attached: req /= Void + do + if attached {WSF_VALUE} req.path_parameter ("orderid") as l_value then + Result := l_value.as_string.value.as_string_8 + else + Result := "" + end + 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_with_string (l_post) + parser.parse_content + if parser.is_valid and then attached parser.parsed_json_value as jv then + if attached {like extract_order_request} json.object (jv, "ORDER") as res then + Result := res + end + end + end + +note + copyright: "2011-2015, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e b/examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e new file mode 100644 index 00000000..4088494e --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/resource/order_handler.e @@ -0,0 +1,403 @@ +note + description: "{ORDER_HANDLER} handle the resources that we want to expose" + author: "" + date: "$Date$" + revision: "$Revision$" + +class ORDER_HANDLER +inherit + + WSF_URI_TEMPLATE_HANDLER + + WSF_RESOURCE_HANDLER_HELPER + redefine + do_get, + do_post, + do_put, + do_delete + end + + SHARED_DATABASE_API + + SHARED_EJSON + + REFACTORING_HELPER + + SHARED_ORDER_VALIDATION + + WSF_SELF_DOCUMENTED_HANDLER + +create + make_with_router + +feature {NONE} -- Initialization + + make_with_router (a_router: WSF_ROUTER) + -- Initialize `router'. + require + a_router_attached: a_router /= Void + do + router := a_router + ensure + router_aliased: router = a_router + end + +feature -- Router + + router: WSF_ROUTER + -- Associated router that could be used for advanced strategy + +feature -- Execute + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute request handler + do + execute_methods (req, res) + end + +feature -- API DOC + + api_doc : STRING = "URI:/order METHOD: POST%N URI:/order/{orderid} METHOD: GET, PUT, DELETE%N" + + +feature -- Documentation + + mapping_documentation (m: WSF_ROUTER_MAPPING; a_request_methods: detachable WSF_REQUEST_METHODS): WSF_ROUTER_MAPPING_DOCUMENTATION + do + create Result.make (m) + if a_request_methods /= Void then + if a_request_methods.has_method_post then + Result.add_description ("URI:/order METHOD: POST") + elseif + a_request_methods.has_method_get + or a_request_methods.has_method_put + or a_request_methods.has_method_delete + then + Result.add_description ("URI:/order/{orderid} METHOD: GET, PUT, DELETE") + end + end + end + +feature -- HTTP Methods + + do_get (req: WSF_REQUEST; res: WSF_RESPONSE) + -- + local + id: STRING + do + if attached req.path_info as l_path_info then + id := get_order_id_from_path (l_path_info) + if attached retrieve_order (id) as l_order then + if is_conditional_get (req, l_order) then + handle_resource_not_modified_response ("The resource" + l_path_info + "does not change", req, res) + else + compute_response_get (req, res, l_order) + end + else + handle_resource_not_found_response ("The following resource" + l_path_info + " is not found ", 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 (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_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.put_header_text (h.string) + res.put_string (l_msg) + end + end + + do_put (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.path_info as l_path_info then + id := get_order_id_from_path (l_path_info) + l_put := retrieve_data (req) + 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 (req, res, l_order) + else + handle_precondition_fail_response ("", 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", 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", 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 (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_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.put_header_text (h.string) + res.put_string (jv.representation) + end + end + + + do_delete (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.path_info as l_path_info then + id := get_order_id_from_path (l_path_info) + if db_access.orders.has_key (id) then + if is_valid_to_delete (id) then + delete_order( id) + compute_response_delete (req, res) + else + --| FIXME: Here we need to define the Allow methods + handle_method_not_allowed_response (l_path_info + "%N There is conflict while trying to delete the order, the order could not be deleted in the current state", req, res) + end + else + handle_resource_not_found_response (l_path_info + " not found in this server", req, res) + end + end + end + + compute_response_delete (req: WSF_REQUEST; res: WSF_RESPONSE) + local + h : HTTP_HEADER + do + create h.make + 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.put_header_text (h.string) + end + + do_post (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 + l_post := retrieve_data (req) + if attached extract_order_request (l_post) as l_order then + save_order (l_order) + compute_response_post (req, res, l_order) + else + handle_bad_request_response (l_post +"%N is not a valid ORDER", req, res) + end + end + + compute_response_post (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_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.put_header_text (h.string) + res.put_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_with_string (l_post) + parser.parse_content + if + parser.is_valid and then + attached parser.parsed_json_value as jv + then + if attached {like extract_order_request} json.object (jv, "ORDER") as res then + Result := res + end + end + end + +note + copyright: "2011-2015, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e b/examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e new file mode 100644 index 00000000..588b2057 --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/restbucks_server.e @@ -0,0 +1,58 @@ +note + description : "REST Buck server" + date : "$Date$" + revision : "$Revision$" + +class RESTBUCKS_SERVER + +inherit + + WSF_ROUTED_SKELETON_SERVICE + undefine + requires_proxy + end + + WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE + + WSF_HANDLER_HELPER + + WSF_DEFAULT_SERVICE + + WSF_NO_PROXY_POLICY + +create + make + +feature {NONE} -- Initialization + + make + do + initialize_router + set_service_option ("port", 9090) + make_and_launch + end + + setup_router + local + order_handler: ORDER_HANDLER + doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER + do + create order_handler.make_with_router (router) + router.handle_with_request_methods ("/order", order_handler, router.methods_POST) + router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT) + create doc.make_hidden (router) + router.handle_with_request_methods ("/api/doc", doc, router.methods_GET) + end + + +note + copyright: "2011-2013, 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 diff --git a/examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e b/examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e new file mode 100644 index 00000000..9aed6c1d --- /dev/null +++ b/examples/obsolete/v0/restbucksCRUD/src/utils/etag_utils.e @@ -0,0 +1,24 @@ +note + description: "Summary description for {ETAG_UTILS}." + date: "$Date$" + revision: "$Revision$" + +class + ETAG_UTILS + +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 + do + create md5.make + md5.update_from_string (a_string) + Result := md5.digest_as_string + end + +note + copyright: "2011-2014, Javier Velilla and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" +end diff --git a/examples/tutorial/README.wiki b/examples/tutorial/README.wiki index 72976e1a..e2d6b9e3 100644 --- a/examples/tutorial/README.wiki +++ b/examples/tutorial/README.wiki @@ -8,10 +8,11 @@ To write once and run on any web server, on any platforms thanks to the notion o == What is a connector? == A connector is the layer between the underlying httpd server, and your application based on EWF. -Currently, 3 connectors are available within EWF (but others are available outside). +Currently, 4 connectors are available within EWF (but others are available outside). *­ CGI: the common CGI application (apache, iis, ...) * FastCGI: on any server supporting libfcgi handling (apache, iis, ...) -* Nino: using the standalone Eiffel Web Nino server, you can run anywhere easily, and debug simply with EiffelStudio's debugger +* Standalone: a standalone Eiffel Web server, it can be run anywhere easily, and debug simply with EiffelStudio's debugger. It supports all concurrency modes, and require EiffelStudio >= 15.05. +* Nino: similar to the "standalone" connectors, but lack good concurrency support. Supporting a new connector is fairly simple, it just has to support the simple EWSGI specification which is really small. Then EWF will bring the power on top of it. diff --git a/examples/tutorial/step_1.wiki b/examples/tutorial/step_1.wiki index 7ab65ede..c9e115c4 100644 --- a/examples/tutorial/step_1.wiki +++ b/examples/tutorial/step_1.wiki @@ -7,12 +7,12 @@ or go to [[step_2.wiki|step 2]] == Get EWF package == === From the archive === -* Get recent archive from https://github.com/EiffelWebFramework/EWF/downloads +* Get recent archive of version v1 from https://github.com/EiffelWebFramework/EWF/releases === From the source === * '''Requirement''': install [http://www.git-scm.org/ git] on your machine - $ git clone --recursive https://github.com/EiffelWebFramework/EWF.git ewf + $ git clone -b v1 --recursive https://github.com/EiffelWebFramework/EWF.git ewf == Install EWF == For now, there is nothing specific to do. diff --git a/examples/tutorial/step_2.wiki b/examples/tutorial/step_2.wiki index c6b759a1..e7b40edb 100644 --- a/examples/tutorial/step_2.wiki +++ b/examples/tutorial/step_2.wiki @@ -13,14 +13,14 @@ or go to [[step_3.wiki|step 3]] == "hello" project == * using the "wsf" library: ** It provides service, request, response, ... -* using the "default_nino" library -** This is used to build the application in a portable manner, but for this compilation, it uses Eiffel Web Nino as connector. -** We use Eiffel Web Nino for this tutorial, because there is no need to configure any apache, iis, and so on. And it is convenient to execute inside EiffelStudio +* using the "default_standalone" library +** This is used to build the application in a portable manner, but for this compilation, it uses the standalone web server as connector. +** We use that standalone connection this tutorial, because there is no need to configure any apache, iis, and so on. And it is convenient to execute with EiffelStudio debugger. * To see the result, you should open http://localhost/ on your web browser. Note if the application is using another port such as 9999, you should open http://localhost:9999/ * You will find inside [[step_2]] the "hello" project -** target "hello" provides a very simple implementation (But by default, it is using port 80 with Eiffel Web Nino, which might already be busy by other application) +** target "hello" provides a very simple implementation (But by default, it is using port 80 with standalone web server, which might already be busy by other application) ** target "hello_custom" which uses almost the same code, but in addition, you can use the ewf.ini file to precise the port number (9999 for this example) * To see the result, open http://localhost/ in a web browser. @@ -28,25 +28,38 @@ or go to [[step_3.wiki|step 3]] * Eiffel code class - HELLO_APPLICATION - + HELLO_APPLICATION + inherit - WSF_DEFAULT_RESPONSE_SERVICE - + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] + create - make_and_launch - - feature {NONE} -- Initialization - - response (req: WSF_REQUEST): WSF_PAGE_RESPONSE - -- Computed response message. - do - create Result.make - Result.put_string ("Hello World") - end + make_and_launch end + class + HELLO_EXECUTION + + inherit + WSF_EXECUTION + + create + make + + feature -- Execution + + execute + local + msg: WSF_PAGE_RESPONSE + do + create msg.make_with_body ("Hello World") + response.send (msg) + end + + end + +Note: we could also declare the root class as being "WSF_DEFAULT_SERVICE [HELLO_EXECUTION]" to avoid this HELLO_APPLICATION class. ---- diff --git a/examples/tutorial/step_2/hello/alternatives/README.wiki b/examples/tutorial/step_2/hello/alternatives/README.wiki index c331a521..f631ce5b 100644 --- a/examples/tutorial/step_2/hello/alternatives/README.wiki +++ b/examples/tutorial/step_2/hello/alternatives/README.wiki @@ -1,11 +1,11 @@ This folder contains 2 alternatives code -1) "execute" using the WSF_SERVICE interface, i.e - execute (req: WSF_REQUEST; res: WSF_RESPONSE) +1) "message" using the WSF_MESSAGE_EXECUTION interface, i.e + message: WSF_RESPONSE_MESSAGE do ... end -2) "launcher" using the WSF_RESPONSE_SERVICE interface, but it uses a launcher to start the service, instead of inheriting from WSF_DEFAULT_SERVICE or WSF_DEFAULT_RESPONSE_SERVICE +2) "launcher" using the WSF_RESPONSE_SERVICE interface, but it uses a launcher to start the service, instead of inheriting from WSF_DEFAULT_SERVICE diff --git a/examples/tutorial/step_2/hello/alternatives/execute/hello_application.e b/examples/tutorial/step_2/hello/alternatives/execute/hello_application.e deleted file mode 100644 index 016aa2ad..00000000 --- a/examples/tutorial/step_2/hello/alternatives/execute/hello_application.e +++ /dev/null @@ -1,39 +0,0 @@ -note - description: "[ - APPLICATION implements the `Hello World' service. - - It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready - only `execute' needs to be implemented. - - `initialize' can be redefine to provide custom options if needed. - - ]" - -class - HELLO_APPLICATION - -inherit - WSF_DEFAULT_SERVICE - -create - make_and_launch - -feature {NONE} -- Initialization - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - local - page: WSF_PAGE_RESPONSE - do - create page.make - page.put_string ("Hello World") - res.send (page) - - --| another alternative would have been more low level - --| by setting the status code, the content type, and the content length which is 11 for "Hello World" - --| res.put_header ({WSF_HEADER}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) - --| res.put_string ("Hello World") - end - - - -end diff --git a/examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.rc b/examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.rc deleted file mode 100644 index 8b137891..00000000 --- a/examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.rc +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/tutorial/step_2/hello/alternatives/launcher/hello_application.e b/examples/tutorial/step_2/hello/alternatives/launcher/hello_application.e index 4dac696c..2eaef500 100644 --- a/examples/tutorial/step_2/hello/alternatives/launcher/hello_application.e +++ b/examples/tutorial/step_2/hello/alternatives/launcher/hello_application.e @@ -11,30 +11,31 @@ class HELLO_APPLICATION inherit - WSF_RESPONSE_SERVICE + WSF_LAUNCHABLE_SERVICE + redefine + initialize + end create make_and_launch feature {NONE} -- Initialization - make_and_launch + initialize local - launcher: WSF_DEFAULT_SERVICE_LAUNCHER opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS do - --| Uncomment the following line, to read options from "ewf.ini" configuration file - -- create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} opts.make_from_file ("ewf.ini") - - create launcher.make_and_launch (Current, opts) + Precursor + --| Uncomment the following 2 lines, to read options from "ewf.ini" configuration file +-- create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} opts.make_from_file ("ewf.ini") +-- import_service_options (opts) end -feature {NONE} -- Initialization - - response (req: WSF_REQUEST): WSF_PAGE_RESPONSE + launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS) + local + launcher: WSF_DEFAULT_SERVICE_LAUNCHER [HELLO_EXECUTION] do - create Result.make - Result.put_string ("Hello World") + create launcher.make_and_launch (opts) end end diff --git a/examples/tutorial/step_2/hello/alternatives/launcher/hello_execution.e b/examples/tutorial/step_2/hello/alternatives/launcher/hello_execution.e new file mode 100644 index 00000000..2f3cd277 --- /dev/null +++ b/examples/tutorial/step_2/hello/alternatives/launcher/hello_execution.e @@ -0,0 +1,35 @@ +note + description: "[ + Request execution for Current application. + Implement `execute' based on `request' and `response'. + ]" + author: "$Author$" + date: "$Date$" + revision: "$Revision$" + +class + HELLO_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Execution + + execute + local + msg: WSF_PAGE_RESPONSE + do + create msg.make_with_body ("Hello World") + response.send (msg) + + --| alternative would have been more low level + --| by setting the content type, and the content length which is 11 for "Hello World" + -- response.header.put_content_type_text_plain + -- response.header.put_content_length (11) + -- response.put_string ("Hello World") + end + +end diff --git a/examples/tutorial/step_2/hello/alternatives/message/hello_application.e b/examples/tutorial/step_2/hello/alternatives/message/hello_application.e new file mode 100644 index 00000000..d1f86da5 --- /dev/null +++ b/examples/tutorial/step_2/hello/alternatives/message/hello_application.e @@ -0,0 +1,21 @@ +note + description: "[ + APPLICATION implements the `Hello World' service. + + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready + only `execute' needs to be implemented. + + `initialize' can be redefine to provide custom options if needed. + + ]" + +class + HELLO_APPLICATION + +inherit + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] + +create + make_and_launch + +end diff --git a/examples/tutorial/step_2/hello/alternatives/message/hello_execution.e b/examples/tutorial/step_2/hello/alternatives/message/hello_execution.e new file mode 100644 index 00000000..1359203b --- /dev/null +++ b/examples/tutorial/step_2/hello/alternatives/message/hello_execution.e @@ -0,0 +1,27 @@ +note + description: "[ + Request execution for Current application. + Implement `message' based on `request' and `response'. + ]" + author: "$Author$" + date: "$Date$" + revision: "$Revision$" + +class + HELLO_EXECUTION + +inherit + WSF_MESSAGE_EXECUTION + +create + make + +feature -- Execution + + message: WSF_PAGE_RESPONSE + do + create Result.make_with_body ("Hello World") + response.send (Result) + end + +end diff --git a/examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.ecf b/examples/tutorial/step_2/hello/alternatives/message/hello_with_execute.ecf similarity index 86% rename from examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.ecf rename to examples/tutorial/step_2/hello/alternatives/message/hello_with_execute.ecf index 9375f810..9a2dbdf0 100644 --- a/examples/tutorial/step_2/hello/alternatives/execute/hello_with_execute.ecf +++ b/examples/tutorial/step_2/hello/alternatives/message/hello_with_execute.ecf @@ -11,9 +11,10 @@ + - + diff --git a/examples/tutorial/step_2/hello/ewf.ini b/examples/tutorial/step_2/hello/ewf.ini index fad6acb1..c29e92cc 100644 --- a/examples/tutorial/step_2/hello/ewf.ini +++ b/examples/tutorial/step_2/hello/ewf.ini @@ -1,4 +1,4 @@ -# For nino connector, use port 9999 +# For standalone connectors, use port 9999 port=9999 #verbose=true diff --git a/examples/tutorial/step_2/hello/hello.ecf b/examples/tutorial/step_2/hello/hello.ecf index 9df56668..097cfbd6 100644 --- a/examples/tutorial/step_2/hello/hello.ecf +++ b/examples/tutorial/step_2/hello/hello.ecf @@ -12,7 +12,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/examples/tutorial/step_2/hello/src/custom_hello_application.e b/examples/tutorial/step_2/hello/src/custom_hello_application.e index 701b91b9..5f0abe5c 100644 --- a/examples/tutorial/step_2/hello/src/custom_hello_application.e +++ b/examples/tutorial/step_2/hello/src/custom_hello_application.e @@ -2,19 +2,17 @@ note description: "[ This class implements the `Hello World' service. - It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready - only `response' needs to be implemented. - In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE - - `initialize' can be redefine to provide custom options if needed. + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready + only `HELLO_EXECUTION' needs to be implemented. + `initialize' is redefined to provide custom options if needed. ]" class CUSTOM_HELLO_APPLICATION inherit - WSF_DEFAULT_RESPONSE_SERVICE + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] redefine initialize end @@ -32,7 +30,7 @@ feature {NONE} -- Initialization --| You can also uncomment the following line if you use the Nino connector --| so that the server listens on port 9999 --| quite often the port 80 is already busy --- set_service_option ("port", 9999) + set_service_option ("port", 9999) --| Uncomment next line to have verbose option if available -- set_service_option ("verbose", True) @@ -41,13 +39,4 @@ feature {NONE} -- Initialization Precursor end -feature {NONE} -- Initialization - - response (req: WSF_REQUEST): WSF_PAGE_RESPONSE - -- Computed response message. - do - create Result.make - Result.put_string ("Hello World") - end - end diff --git a/examples/tutorial/step_2/hello/src/hello_application.e b/examples/tutorial/step_2/hello/src/hello_application.e index 41f77b0a..484fba8e 100644 --- a/examples/tutorial/step_2/hello/src/hello_application.e +++ b/examples/tutorial/step_2/hello/src/hello_application.e @@ -2,30 +2,20 @@ note description: "[ This class implements the `Hello World' service. - It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready - only `response' needs to be implemented. - In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE - - `initialize' can be redefine to provide custom options if needed. + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready. + And implement HELLO_EXECUTION. + `initialize' can be redefine to provide custom options if needed, + such as specific port number. ]" class HELLO_APPLICATION inherit - WSF_DEFAULT_RESPONSE_SERVICE + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] create make_and_launch -feature {NONE} -- Initialization - - response (req: WSF_REQUEST): WSF_PAGE_RESPONSE - -- Computed response message. - do - create Result.make - Result.put_string ("Hello World") - end - end diff --git a/examples/tutorial/step_2/hello/src/hello_execution.e b/examples/tutorial/step_2/hello/src/hello_execution.e new file mode 100644 index 00000000..2f3cd277 --- /dev/null +++ b/examples/tutorial/step_2/hello/src/hello_execution.e @@ -0,0 +1,35 @@ +note + description: "[ + Request execution for Current application. + Implement `execute' based on `request' and `response'. + ]" + author: "$Author$" + date: "$Date$" + revision: "$Revision$" + +class + HELLO_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Execution + + execute + local + msg: WSF_PAGE_RESPONSE + do + create msg.make_with_body ("Hello World") + response.send (msg) + + --| alternative would have been more low level + --| by setting the content type, and the content length which is 11 for "Hello World" + -- response.header.put_content_type_text_plain + -- response.header.put_content_length (11) + -- response.put_string ("Hello World") + end + +end diff --git a/examples/tutorial/step_3.wiki b/examples/tutorial/step_3.wiki index 5ed8dd00..d4858565 100644 --- a/examples/tutorial/step_3.wiki +++ b/examples/tutorial/step_3.wiki @@ -11,12 +11,12 @@ or go to [[step_4.wiki|step 4]] == "hello" project == * Let's start from the "hello_custom" project -* you will learn how to use the req: WSF_REQUEST argument +* you will learn how to use the request: WSF_REQUEST argument * See the hello project from [[step_3|step #3]] folder * You can find code in [[step_3]] folder : - response (req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE + message: WSF_HTML_PAGE_RESPONSE -- Computed response message. do --| It is now returning a WSF_HTML_PAGE_RESPONSE @@ -25,7 +25,7 @@ or go to [[step_4.wiki|step 4]] Result.set_title ("EWF tutorial / Hello World!") --| Check if the request contains a parameter named "user" --| this could be a query, or a form parameter - if attached req.string_item ("user") as l_user then + if attached request.string_item ("user") as l_user then --| If yes, say hello world #name Result.set_body ("Hello " + l_user + "!") --| We should html encode this name @@ -43,8 +43,8 @@ or go to [[step_4.wiki|step 4]] end --| note: --| 1) Source of the parameter, we could have used - --| req.query_parameter ("user") to search only in the query string - --| req.form_parameter ("user") to search only in the form parameters + --| request.query_parameter ("user") to search only in the query string + --| request.form_parameter ("user") to search only in the form parameters --| 2) response type --| it could also have used WSF_PAGE_REPONSE, and build the html in the code --| diff --git a/examples/tutorial/step_3/hello/hello.ecf b/examples/tutorial/step_3/hello/hello.ecf index b58272ca..000c2d3b 100644 --- a/examples/tutorial/step_3/hello/hello.ecf +++ b/examples/tutorial/step_3/hello/hello.ecf @@ -15,7 +15,7 @@ - + diff --git a/examples/tutorial/step_3/hello/src/hello_application.e b/examples/tutorial/step_3/hello/src/hello_application.e index 6220e3f7..bbaea8a1 100644 --- a/examples/tutorial/step_3/hello/src/hello_application.e +++ b/examples/tutorial/step_3/hello/src/hello_application.e @@ -1,10 +1,9 @@ note description: "[ - This class implements the `Hello World' service. + This class launch the HELLO_EXECUTION service. - It inherits from WSF_DEFAULT_RESPONSE_SERVICE to get default EWF connector ready - only `response' needs to be implemented. - In this example, it is redefined and specialized to be WSF_PAGE_RESPONSE + It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready + only `HELLO_EXECUTION' needs to be implemented. `initialize' can be redefine to provide custom options if needed. @@ -14,7 +13,7 @@ class HELLO_APPLICATION inherit - WSF_DEFAULT_RESPONSE_SERVICE + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] redefine initialize end @@ -22,44 +21,6 @@ inherit create make_and_launch -feature {NONE} -- Execution - - response (req: WSF_REQUEST): WSF_HTML_PAGE_RESPONSE - -- Computed response message. - do - --| It is now returning a WSF_HTML_PAGE_RESPONSE - --| Since it is easier for building html page - create Result.make - Result.set_title ("EWF tutorial / Hello World!") - --| Check if the request contains a parameter named "user" - --| this could be a query, or a form parameter - if attached req.string_item ("user") as l_user then - --| If yes, say hello world #name - Result.set_body ("Hello " + l_user + "!") - --| We should html encode this name - --| but to keep the example simple, we don't do that for now. - else - --| Otherwise, ask for name - Result.set_body ("[ -
-

Hello, what is your name?

- - -
- ]" - ) - end - - --| note: - --| 1) Source of the parameter, we could have used - --| req.query_parameter ("user") to search only in the query string - --| req.form_parameter ("user") to search only in the form parameters - --| 2) response type - --| it could also have used WSF_PAGE_REPONSE, and build the html in the code - --| - - end - feature {NONE} -- Initialization initialize diff --git a/examples/tutorial/step_3/hello/src/hello_execution.e b/examples/tutorial/step_3/hello/src/hello_execution.e new file mode 100644 index 00000000..652829db --- /dev/null +++ b/examples/tutorial/step_3/hello/src/hello_execution.e @@ -0,0 +1,53 @@ +note + description: "Implementation of Hello world with form." + date: "$Date$" + revision: "$Revision$" + +class + HELLO_EXECUTION + +inherit + WSF_MESSAGE_EXECUTION + +create + make + +feature {NONE} -- Execution + + message: WSF_HTML_PAGE_RESPONSE + -- Computed response message. + do + --| It is now returning a WSF_HTML_PAGE_RESPONSE + --| Since it is easier for building html page + create Result.make + Result.set_title ("EWF tutorial / Hello World!") + --| Check if the request contains a parameter named "user" + --| this could be a query, or a form parameter + if attached request.string_item ("user") as l_user then + --| If yes, say hello world #name + Result.set_body ("Hello " + l_user + "!") + --| We should html encode this name + --| but to keep the example simple, we don't do that for now. + else + --| Otherwise, ask for name + Result.set_body ("[ +
+

Hello, what is your name?

+ + +
+ ]" + ) + end + + --| note: + --| 1) Source of the parameter, we could have used + --| request.query_parameter ("user") to search only in the query string + --| request.form_parameter ("user") to search only in the form parameters + --| 2) response type + --| it could also have used WSF_PAGE_REPONSE, and build the html in the code + --| + + end + +end diff --git a/examples/tutorial/step_4.wiki b/examples/tutorial/step_4.wiki index 936424eb..8ee9f185 100644 --- a/examples/tutorial/step_4.wiki +++ b/examples/tutorial/step_4.wiki @@ -11,30 +11,30 @@ or go to the [[README.wiki|index]] == "hello" project == * Let's start from the "hello" project -* you will learn how to use the req: WSF_ROUTER component +* you will learn how to use the WSF_ROUTER component * See the hello project from [[step_4|step #4]] folder * You can find code in [[step_4]] folder : - To get a routed service based on URI Template, your service application class should inherit from WSF_URI_TEMPLATE_ROUTED_SERVICE - then you need to implement "setup_router", the following code is from the step_4 example + To get a routed execution based on URI Template, your execution class should inherit from WSF_URI_TEMPLATE_ROUTED_EXECUTION + then you need to implement "setup_router". In addition you can inherit from WSF_ROUTED_URI_HELPER and WSF_ROUTED_URI_TEMPLATE_HELPER, in order to call user-friendly routine provided to work easily with uri, or uri-template mapping. the following code is from the step_4 example setup_router do - router.map_agent ("/hello", agent execute_hello) + map_uri_agent ("/hello", agent execute_hello, Void) - router.map_with_request_methods ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) - router.map_with_request_methods ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) + map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) + map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, <<"GET", "POST">>) - router.map_agent_response_with_request_methods ("/users/{user}/{?op}", agent response_user, <<"GET">>) + map_uri_template_response_agent ("/users/{user}/{?op}", agent response_user, <<"GET">>) end * map_agent is used to handle the url /hello with the feature "execute_hello" -* map_agent_response_with_request_methods is similar but you precise the accepted request methods -* map and map_with_request_method are similar to previous "agent" variant, but it is using a descendant of WSF_HANDLER to handle the related url. +* map_agent_response is similar but you precise the accepted request methods +* map is similar to previous "agent" variant, but it is using a descendant of WSF_HANDLER to handle the related request. -* In this example, we use the URI Template router, this allows to define the route using resource like /user/{user} , and then you get access to the "user" data from the WSF_REQUEST.path_parameter or using the context argument passed for the execute or response handler. +* In this example, we use the URI-Template router, this allows to define the route using resource like /user/{user} , and then you get access to the "user" data from the WSF_REQUEST.path_parameter or using the context argument passed for the execute or response handler. * The example also includes basic notions of url, html encoding, check the hello.ecf to see the added libraries (http to get easy access to the http status code, encoder for simple encoding components) ---- diff --git a/examples/tutorial/step_4/hello/hello.ecf b/examples/tutorial/step_4/hello/hello.ecf index 37cfd5d0..903ba32d 100644 --- a/examples/tutorial/step_4/hello/hello.ecf +++ b/examples/tutorial/step_4/hello/hello.ecf @@ -12,7 +12,7 @@ - + diff --git a/examples/tutorial/step_4/hello/src/hello_application.e b/examples/tutorial/step_4/hello/src/hello_application.e index 3d0024a5..9e68dd41 100644 --- a/examples/tutorial/step_4/hello/src/hello_application.e +++ b/examples/tutorial/step_4/hello/src/hello_application.e @@ -3,7 +3,6 @@ This class implements the `Hello World' service. It inherits from WSF_DEFAULT_SERVICE to get default EWF connector ready - And from WSF_URI_TEMPLATE_ROUTED_SERVICE to use the router service `initialize' can be redefine to provide custom options if needed. @@ -13,9 +12,7 @@ class HELLO_APPLICATION inherit - WSF_ROUTED_SERVICE - - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [HELLO_EXECUTION] redefine initialize end @@ -23,136 +20,6 @@ inherit create make_and_launch -feature {NONE} -- Initialization - - setup_router - do --- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello))) - map_agent_uri ("/hello", agent execute_hello, Void) - --- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST) - map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST) - --- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}), router.methods_GET_POST) - map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST) - --- router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/{?op}", create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (agent response_user)), router.methods_GET) - map_agent_uri_template_response ("/users/{user}/{?op}", agent response_user, router.methods_GET) - end - -feature -- Helper: mapping - - map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) - do - router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods) - end - - map_uri_template (a_tpl: READABLE_STRING_8; a_handler: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) - do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, a_handler), rqst_methods) - end - - map_agent_uri_template_response (a_tpl: READABLE_STRING_8; a_action: like {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) - do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, create {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.make (a_action)), rqst_methods) - end - -feature -- Execution - - execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Computed response message. - local - mesg: WSF_HTML_PAGE_RESPONSE - s: STRING_8 - l_user_name: READABLE_STRING_32 - do - --| It is now returning a WSF_HTML_PAGE_RESPONSE - --| Since it is easier for building html page - create mesg.make - mesg.set_title ("EWF tutorial / Hello World!") - --| Check if the request contains a parameter named "user" - --| this could be a query, or a form parameter - if attached {WSF_STRING} req.item ("user") as u then - --| If yes, say hello world #name - - l_user_name := (create {HTML_ENCODER}).decoded_string (u.value) - - s := "

Hello " + mesg.html_encoded_string (l_user_name) + "!

" - s.append ("Display a message

") - s.append ("

Click here to quit.

") - mesg.set_body (s) - --| We should html encode this name - --| but to keep the example simple, we don't do that for now. - else - --| Otherwise, ask for name - s := (create {HTML_ENCODER}).encoded_string ({STRING_32} "Hello / ahoj / नमस्ते / Ciào / مرحبا / Hola / 你好 / Hallo / Selam / Bonjour ") - s.append ("[ -
- What is your name?

- - -
- ]" - ) - mesg.set_body (s) - end - - --| note: - --| 1) Source of the parameter, we could have used - --| req.query_parameter ("user") to search only in the query string - --| req.form_parameter ("user") to search only in the form parameters - --| 2) response type - --| it could also have used WSF_PAGE_REPONSE, and build the html in the code - --| - - res.send (mesg) - end - - response_user (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE - -- Computed response message. - local - html: WSF_HTML_PAGE_RESPONSE - redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE - s: STRING_8 - l_username: STRING_32 - do - if attached {WSF_STRING} req.path_parameter ("user") as u then - l_username := (create {HTML_ENCODER}).general_decoded_string (u.value) - if - attached {WSF_STRING} req.query_parameter ("op") as l_op - then - if l_op.is_case_insensitive_equal ("quit") then - create redir.make (req.script_url ("/hello"), 3) - create html.make - redir.set_title ("Bye " + html.html_encoded_string (l_username)) - redir.set_body ("Bye " + html.html_encoded_string (l_username) + ",
see you soon.

You will be redirected to " + - redir.url_location + " in " + redir.delay.out + " second(s) ...

" - ) - Result := redir - else - create html.make - html.set_title ("Bad request") - html.set_body ("Bad request: unknown operation '" + l_op.url_encoded_value + "'.") - Result := html - end - else - create html.make - - s := "

User '" + html.html_encoded_string (l_username) + "'!

" - s.append ("Display a message

") - s.append ("

Click here to quit.

") - html.set_title ("User '" + u.url_encoded_value + "'") - html.set_body (s) - Result := html - end - else - create html.make - html.set_title ("Bad request") - html.set_body ("Bad request: missing user parameter") - Result := html - end - end - feature {NONE} -- Initialization initialize @@ -163,8 +30,6 @@ feature {NONE} -- Initialization --| If you don't need any custom options, you are not obliged to redefine `initialize' Precursor - --| Initialize router - initialize_router end diff --git a/examples/tutorial/step_4/hello/src/hello_execution.e b/examples/tutorial/step_4/hello/src/hello_execution.e new file mode 100644 index 00000000..82767817 --- /dev/null +++ b/examples/tutorial/step_4/hello/src/hello_execution.e @@ -0,0 +1,135 @@ +note + description: "[ + This class implements the `Hello World' execution service. + + It inherits from WSF_ROUTED_EXECUTION to use the router service + and from WSF_ROUTED_URI_TEMPLATE_HELPER to use help feature to map + uri-template routes + ]" + +class + HELLO_EXECUTION + +inherit + WSF_ROUTED_EXECUTION + + WSF_ROUTED_URI_HELPER + WSF_ROUTED_URI_TEMPLATE_HELPER + +create + make + +feature {NONE} -- Initialization + + setup_router + do +-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello))) + map_uri_agent ("/hello", agent execute_hello) + +-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST) + map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST) + +-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}), router.methods_GET_POST) + map_uri_template ("/users/{user}/message/", create {USER_MESSAGE_HANDLER}, router.methods_GET_POST) + +-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/{?op}", create {WSF_AGENT_URI_TEMPLATE_RESPONSE_HANDLER}.make (agent response_user)), router.methods_GET) + map_uri_template_response_agent ("/users/{user}/{?op}", agent response_user, router.methods_GET) + end + +feature -- Execution + + execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Computed response message. + local + mesg: WSF_HTML_PAGE_RESPONSE + s: STRING_8 + l_user_name: READABLE_STRING_32 + do + --| It is now returning a WSF_HTML_PAGE_RESPONSE + --| Since it is easier for building html page + create mesg.make + mesg.set_title ("EWF tutorial / Hello World!") + --| Check if the request contains a parameter named "user" + --| this could be a query, or a form parameter + if attached {WSF_STRING} req.item ("user") as u then + --| If yes, say hello world #name + + l_user_name := (create {HTML_ENCODER}).decoded_string (u.value) + + s := "

Hello " + mesg.html_encoded_string (l_user_name) + "!

" + s.append ("Display a message

") + s.append ("

Click here to quit.

") + mesg.set_body (s) + --| We should html encode this name + --| but to keep the example simple, we don't do that for now. + else + --| Otherwise, ask for name + s := (create {HTML_ENCODER}).encoded_string ({STRING_32} "Hello / ahoj / नमस्ते / Ciào / مرحبا / Hola / 你好 / Hallo / Selam / Bonjour ") + s.append ("[ +
+ What is your name?

+ + +
+ ]" + ) + mesg.set_body (s) + end + + --| note: + --| 1) Source of the parameter, we could have used + --| req.query_parameter ("user") to search only in the query string + --| req.form_parameter ("user") to search only in the form parameters + --| 2) response type + --| it could also have used WSF_PAGE_REPONSE, and build the html in the code + --| + + res.send (mesg) + end + + response_user (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE + -- Computed response message. + local + html: WSF_HTML_PAGE_RESPONSE + redir: WSF_HTML_DELAYED_REDIRECTION_RESPONSE + s: STRING_8 + l_username: STRING_32 + do + if attached {WSF_STRING} req.path_parameter ("user") as u then + l_username := (create {HTML_ENCODER}).general_decoded_string (u.value) + if + attached {WSF_STRING} req.query_parameter ("op") as l_op + then + if l_op.is_case_insensitive_equal ("quit") then + create redir.make (req.script_url ("/hello"), 3) + create html.make + redir.set_title ("Bye " + html.html_encoded_string (l_username)) + redir.set_body ("Bye " + html.html_encoded_string (l_username) + ",
see you soon.

You will be redirected to " + + redir.url_location + " in " + redir.delay.out + " second(s) ...

" + ) + Result := redir + else + create html.make + html.set_title ("Bad request") + html.set_body ("Bad request: unknown operation '" + l_op.url_encoded_value + "'.") + Result := html + end + else + create html.make + + s := "

User '" + html.html_encoded_string (l_username) + "'!

" + s.append ("Display a message

") + s.append ("

Click here to quit.

") + html.set_title ("User '" + u.url_encoded_value + "'") + html.set_body (s) + Result := html + end + else + create html.make + html.set_title ("Bad request") + html.set_body ("Bad request: missing user parameter") + Result := html + end + end + +end diff --git a/examples/upload_image/src/image_uploader_execution.e b/examples/upload_image/src/image_uploader_execution.e index 6cfe5184..06161243 100644 --- a/examples/upload_image/src/image_uploader_execution.e +++ b/examples/upload_image/src/image_uploader_execution.e @@ -38,7 +38,7 @@ feature {NONE} -- Initialization www: WSF_FILE_SYSTEM_HANDLER do map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put) - map_uri_template_agent ("/upload{?nb}", agent execute_upload) + map_uri_template_agent ("/upload{?nb}", agent execute_upload, Void) create www.make_with_path (document_root) www.set_directory_index (<<"index.html">>) diff --git a/library/security/openid/consumer/demo/application_execution.e b/library/security/openid/consumer/demo/application_execution.e index 15e9396b..1220c82a 100644 --- a/library/security/openid/consumer/demo/application_execution.e +++ b/library/security/openid/consumer/demo/application_execution.e @@ -29,8 +29,8 @@ feature {NONE} -- Initialization setup_router do - map_uri_template_agent ("/", agent handle_root) - map_uri_template_agent ("/openid", agent handle_openid) + map_uri_template_agent ("/", agent handle_root, Void) + map_uri_template_agent ("/openid", agent handle_openid, Void) end handle_root (req: WSF_REQUEST; res: WSF_RESPONSE) diff --git a/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e b/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e index 0e1cfd84..b2c5bfe9 100644 --- a/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e +++ b/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e @@ -23,6 +23,14 @@ feature -- Mapping helper: uri router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) end + map_uri_response (a_uri: READABLE_STRING_8; h: WSF_URI_RESPONSE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `h' as response handler for `a_uri' for request methods `rqst_methods'. + require + h_attached: h /= Void + do + router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) + end + feature -- Mapping helper: uri agent map_uri_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) @@ -37,6 +45,14 @@ feature -- Mapping helper: uri agent map_uri_with_request_methods (a_uri, create {WSF_URI_AGENT_HANDLER}.make (proc), rqst_methods) end + map_uri_response_agent (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `a_action' as response handler for `a_uri' for request methods `rqst_methods'. + require + a_action_attached: a_action /= Void + do + map_uri_response (a_uri, create {WSF_URI_RESPONSE_AGENT_HANDLER}.make (a_action), rqst_methods) + end + note copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/server/wsf/router/support/uri/helpers/wsf_uri_response_agent_handler.e b/library/server/wsf/router/support/uri/helpers/wsf_uri_response_agent_handler.e new file mode 100644 index 00000000..8bc0b5e4 --- /dev/null +++ b/library/server/wsf/router/support/uri/helpers/wsf_uri_response_agent_handler.e @@ -0,0 +1,44 @@ +note + description: "Summary description for {WSF_URI_RESPONSE_AGENT_HANDLER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_URI_RESPONSE_AGENT_HANDLER + +inherit + WSF_URI_RESPONSE_HANDLER + +create + make + +feature -- Initialization + + make (act: like action) + do + action := act + end + +feature -- Access + + action: FUNCTION [ANY, TUPLE [req: WSF_REQUEST], WSF_RESPONSE_MESSAGE] + +feature -- Execution + + response (req: WSF_REQUEST): WSF_RESPONSE_MESSAGE + do + Result := action.item ([req]) + end + +note + copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e b/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e index 7ed42435..12152825 100644 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e @@ -11,42 +11,64 @@ inherit feature -- Mapping helper: uri template - map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER) - -- Map `h' as handler for `a_tpl' + map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `h' as handler for `a_tpl'. require a_tpl_attached: a_tpl /= Void h_attached: h /= Void do - map_uri_template_with_request_methods (a_tpl, h, Void) + router.map (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) end map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `h' as handler for `a_tpl' for request methods `rqst_methods'. + obsolete + "Use directly `map_uri_template' [June/2015]" require a_tpl_attached: a_tpl /= Void h_attached: h /= Void do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) + map_uri_template (a_tpl, h, rqst_methods) + end + + map_uri_template_response (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_RESPONSE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `h' as response handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + h_attached: h /= Void + do + router.map (create {WSF_URI_TEMPLATE_MAPPING}.make (a_tpl, h), rqst_methods) end feature -- Mapping helper: uri template agent - map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) + map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `proc' as handler for `a_tpl' require a_tpl_attached: a_tpl /= Void proc_attached: proc /= Void do - map_uri_template_agent_with_request_methods (a_tpl, proc, Void) + map_uri_template (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) end map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `proc' as handler for `a_tpl' for request methods `rqst_methods'. + obsolete + "Use directly `map_uri_template_agent' [June/2015]" require a_tpl_attached: a_tpl /= Void proc_attached: proc /= Void do - map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (proc), rqst_methods) + map_uri_template_agent (a_tpl, proc, rqst_methods) + end + + map_uri_template_response_agent (a_tpl: READABLE_STRING_8; a_action: like {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `a_action' as response handler for `a_tpl' for request methods `rqst_methods'. + require + a_tpl_attached: a_tpl /= Void + a_action_attached: a_action /= Void + do + map_uri_template_response (a_tpl, create {WSF_URI_TEMPLATE_RESPONSE_AGENT_HANDLER}.make (a_action), rqst_methods) end note diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index df7d4b43..4b6e2deb 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -64,20 +64,22 @@ feature {NONE} -- Initialization feature -- Mapping - map (a_mapping: WSF_ROUTER_MAPPING) + map (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `a_mapping'. require a_mapping_attached: a_mapping /= Void do - map_with_request_methods (a_mapping, Void) + extend (create {WSF_ROUTER_ITEM}.make_with_request_methods (a_mapping, rqst_methods)) end map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `a_mapping' for request methods `rqst_methods'. + obsolete + "Use directly `map' [June/2015]" require a_mapping_attached: a_mapping /= Void do - extend (create {WSF_ROUTER_ITEM}.make_with_request_methods (a_mapping, rqst_methods)) + map (a_mapping, rqst_methods) end import (a_mapping_items: ITERABLE [WSF_ROUTER_ITEM]) @@ -116,23 +118,25 @@ feature {WSF_ROUTER} -- Mapping feature -- Mapping handler - handle (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY) + handle (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map the mapping created by factory `f' for resource `a_resource'. require a_resource_attached: a_resource /= Void f_attached: f /= Void do - handle_with_request_methods (a_resource, f, Void) + map (f.new_mapping (a_resource), rqst_methods) end handle_with_request_methods (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map the mapping created by factory `f' for resource `a_resource' -- and only for request methods `rqst_methods' + obsolete + "Use directly `handle' [June/2015]" require a_resource_attached: a_resource /= Void f_attached: f /= Void do - map_with_request_methods (f.new_mapping (a_resource), rqst_methods) + handle (a_resource, f, rqst_methods) end feature -- Basic operations diff --git a/library/server/wsf/src/service/wsf_launchable_service.e b/library/server/wsf/src/service/wsf_launchable_service.e index 385ee1fa..1c6cff4b 100644 --- a/library/server/wsf/src/service/wsf_launchable_service.e +++ b/library/server/wsf/src/service/wsf_launchable_service.e @@ -37,6 +37,16 @@ feature -- Basic operation feature -- Default service options + import_service_options (opts: WSF_SERVICE_LAUNCHER_OPTIONS) + -- Import service options `opts' into `service_options'. + do + if attached service_options as l_opts then + l_opts.append_options (opts) + else + service_options := opts + end + end + set_service_option (a_name: READABLE_STRING_GENERAL; a_value: detachable ANY) -- Set options related to WSF_SERVICE_LAUNCHER local diff --git a/library/server/wsf/src/wsf_message_execution.e b/library/server/wsf/src/wsf_message_execution.e new file mode 100644 index 00000000..704b1a48 --- /dev/null +++ b/library/server/wsf/src/wsf_message_execution.e @@ -0,0 +1,40 @@ +note + description: "[ + Request execution based on attributes `request' and `response'. + And returning the response as a `message'. + ]" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_MESSAGE_EXECUTION + +inherit + WSF_EXECUTION + +feature -- Execution + + execute + -- + do + response.send (message) + end + + message: WSF_RESPONSE_MESSAGE + -- Message to be sent to the `response'. + deferred + ensure + Result_set: Result /= Void + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, 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/tools/install_ewf.bat b/tools/install_ewf.bat index be11a064..ff75cdc2 100644 --- a/tools/install_ewf.bat +++ b/tools/install_ewf.bat @@ -64,6 +64,10 @@ echo Install library: ewf/wsf_html echo Install library: ewf/encoder %COPYCMD% %TMP_DIR%\library\text\encoder %TMP_CONTRIB_DIR%\library\web\framework\ewf\text\encoder + +echo Install library: ewf/obsolete +%COPYCMD% %TMP_DIR%\library\server\obsolete %TMP_CONTRIB_DIR%\library\web\framework\ewf\obsolete + echo Install examples %SAFE_MD% %TMP_CONTRIB_DIR%\examples %SAFE_MD% %TMP_CONTRIB_DIR%\examples\web From ab0bc7b31476b9779a64c228501d693c8688bd54 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 10 Jun 2015 17:52:26 +0200 Subject: [PATCH 03/36] Marked most of the *_with_request_methods procedure obsolete by the same feature name without the "_with_request_methods". Added argument passing request methods to feature without the _with_request_methods. Prefer "thread" concurrency for now in examples. --- .../examples/demo/application_execution.e | 4 ++-- examples/debug/debug.ecf | 4 ++-- examples/desktop_app/desktop_app.ecf | 2 +- .../src/app_embedded_web_execution.e | 8 +++---- examples/filter/filter-safe.ecf | 2 +- examples/filter/src/filter_server_execution.e | 2 +- examples/restbucksCRUD/restbucks-safe.ecf | 2 +- .../src/restbucks_server_execution.e | 6 ++--- examples/simple/simple.ecf | 2 +- examples/simple_file/service_file.ecf | 2 +- .../src/image_uploader_execution.e | 4 ++-- .../uri/helpers/wsf_routed_uri_helper.e | 22 +++++++++++-------- .../helpers/wsf_routed_uri_template_helper.e | 4 ++-- library/server/wsf/router/wsf_router.e | 8 +++++-- library/server/wsf/router/wsf_router_item.e | 12 +++------- .../wsf_starts_with_context_router_helper.e | 18 +++++++++------ .../helpers/wsf_uri_context_router_helper.e | 18 +++++++++------ .../wsf_uri_template_context_router_helper.e | 18 +++++++++------ 18 files changed, 76 insertions(+), 62 deletions(-) diff --git a/draft/library/server/wsf_js_widget/examples/demo/application_execution.e b/draft/library/server/wsf_js_widget/examples/demo/application_execution.e index 564f5c85..f52ea971 100644 --- a/draft/library/server/wsf_js_widget/examples/demo/application_execution.e +++ b/draft/library/server/wsf_js_widget/examples/demo/application_execution.e @@ -38,14 +38,14 @@ feature -- Router and Filter -- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/" -- this way, it handles the caching and so on - router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET) + router.handle ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET) end feature -- Helper: mapping map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) do - router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods) + router.map (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods) end feature -- Execution diff --git a/examples/debug/debug.ecf b/examples/debug/debug.ecf index 5c6d642c..948e3e8e 100644 --- a/examples/debug/debug.ecf +++ b/examples/debug/debug.ecf @@ -18,7 +18,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/examples/desktop_app/desktop_app.ecf b/examples/desktop_app/desktop_app.ecf index 81a0aa50..6ba18b3f 100644 --- a/examples/desktop_app/desktop_app.ecf +++ b/examples/desktop_app/desktop_app.ecf @@ -7,7 +7,7 @@ - + diff --git a/examples/desktop_app/src/app_embedded_web_execution.e b/examples/desktop_app/src/app_embedded_web_execution.e index 815e35a6..50f0a87a 100644 --- a/examples/desktop_app/src/app_embedded_web_execution.e +++ b/examples/desktop_app/src/app_embedded_web_execution.e @@ -45,11 +45,11 @@ feature -- Execution req := request create router.make (3) - router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test)) - router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env)) - router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit)) + router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test), Void) + router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env), Void) + router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit), Void) create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files")) - router.handle ("/files", fs) + router.handle ("/files", fs, Void) create sess router.dispatch (req, response, sess) if not sess.dispatched then diff --git a/examples/filter/filter-safe.ecf b/examples/filter/filter-safe.ecf index 6d85dcd0..cf802a06 100644 --- a/examples/filter/filter-safe.ecf +++ b/examples/filter/filter-safe.ecf @@ -27,7 +27,7 @@ - + diff --git a/examples/filter/src/filter_server_execution.e b/examples/filter/src/filter_server_execution.e index 21727ede..4081d291 100644 --- a/examples/filter/src/filter_server_execution.e +++ b/examples/filter/src/filter_server_execution.e @@ -59,7 +59,7 @@ feature {NONE} -- Initialization create l_methods l_methods.enable_options l_methods.enable_get - router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods) + router.handle ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods) end initialize_json diff --git a/examples/restbucksCRUD/restbucks-safe.ecf b/examples/restbucksCRUD/restbucks-safe.ecf index acf2f5dd..9a8a9a6e 100644 --- a/examples/restbucksCRUD/restbucks-safe.ecf +++ b/examples/restbucksCRUD/restbucks-safe.ecf @@ -8,7 +8,7 @@
- + - + diff --git a/examples/simple_file/service_file.ecf b/examples/simple_file/service_file.ecf index 9674713e..7f39a526 100644 --- a/examples/simple_file/service_file.ecf +++ b/examples/simple_file/service_file.ecf @@ -5,7 +5,7 @@ - + diff --git a/examples/upload_image/src/image_uploader_execution.e b/examples/upload_image/src/image_uploader_execution.e index 06161243..6e5ac13d 100644 --- a/examples/upload_image/src/image_uploader_execution.e +++ b/examples/upload_image/src/image_uploader_execution.e @@ -37,13 +37,13 @@ feature {NONE} -- Initialization local www: WSF_FILE_SYSTEM_HANDLER do - map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put) + map_uri_template_agent ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put) map_uri_template_agent ("/upload{?nb}", agent execute_upload, Void) create www.make_with_path (document_root) www.set_directory_index (<<"index.html">>) www.set_not_found_handler (agent execute_not_found) - router.handle_with_request_methods ("", www, router.methods_GET) + router.handle ("", www, router.methods_GET) end feature -- Configuration diff --git a/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e b/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e index b2c5bfe9..e44ef2b5 100644 --- a/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e +++ b/library/server/wsf/router/support/uri/helpers/wsf_routed_uri_helper.e @@ -11,16 +11,18 @@ inherit feature -- Mapping helper: uri - map_uri (a_uri: READABLE_STRING_8; h: WSF_URI_HANDLER) - -- Map `h' as handler for `a_uri' + map_uri (a_uri: READABLE_STRING_8; h: WSF_URI_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `h' as handler for `a_uri', according to `rqst_methods'. do - map_uri_with_request_methods (a_uri, h, Void) + router.map (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) end map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `h' as handler for `a_uri' for request methods `rqst_methods'. + obsolete + "Use directly `map_uri' [June/2015]" do - router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) + map_uri (a_uri, h, rqst_methods) end map_uri_response (a_uri: READABLE_STRING_8; h: WSF_URI_RESPONSE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) @@ -28,21 +30,23 @@ feature -- Mapping helper: uri require h_attached: h /= Void do - router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) + router.map (create {WSF_URI_MAPPING}.make (a_uri, h), rqst_methods) end feature -- Mapping helper: uri agent - map_uri_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]) - -- Map `proc' as handler for `a_uri' + map_uri_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) + -- Map `proc' as handler for `a_uri', according to `rqst_methods'. do - map_uri_agent_with_request_methods (a_uri, proc, Void) + map_uri (a_uri, create {WSF_URI_AGENT_HANDLER}.make (proc), rqst_methods) end map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map `proc' as handler for `a_uri' for request methods `rqst_methods'. + obsolete + "Use directly `map_uri_agent' [June/2015]" do - map_uri_with_request_methods (a_uri, create {WSF_URI_AGENT_HANDLER}.make (proc), rqst_methods) + map_uri_agent (a_uri, proc, rqst_methods) end map_uri_response_agent (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_RESPONSE_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS) diff --git a/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e b/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e index 12152825..76f8d7ea 100644 --- a/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e +++ b/library/server/wsf/router/support/uri_template/helpers/wsf_routed_uri_template_helper.e @@ -12,7 +12,7 @@ inherit feature -- Mapping helper: uri template map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER; rqst_methods: detachable WSF_REQUEST_METHODS) - -- Map `h' as handler for `a_tpl'. + -- Map `h' as handler for `a_tpl', according to `rqst_methods'. require a_tpl_attached: a_tpl /= Void h_attached: h /= Void @@ -43,7 +43,7 @@ feature -- Mapping helper: uri template feature -- Mapping helper: uri template agent map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) - -- Map `proc' as handler for `a_tpl' + -- Map `proc' as handler for `a_tpl', according to `rqst_methods'. require a_tpl_attached: a_tpl /= Void proc_attached: proc /= Void diff --git a/library/server/wsf/router/wsf_router.e b/library/server/wsf/router/wsf_router.e index 4b6e2deb..78293969 100644 --- a/library/server/wsf/router/wsf_router.e +++ b/library/server/wsf/router/wsf_router.e @@ -65,11 +65,13 @@ feature {NONE} -- Initialization feature -- Mapping map (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) - -- Map `a_mapping'. + -- Map `a_mapping', + -- if `rqst_methods' is set, accept only request method in `rqst_methods'. + -- if `rqst_method' is Void, accept any request methods. require a_mapping_attached: a_mapping /= Void do - extend (create {WSF_ROUTER_ITEM}.make_with_request_methods (a_mapping, rqst_methods)) + extend (create {WSF_ROUTER_ITEM}.make (a_mapping, rqst_methods)) end map_with_request_methods (a_mapping: WSF_ROUTER_MAPPING; rqst_methods: detachable WSF_REQUEST_METHODS) @@ -120,6 +122,8 @@ feature -- Mapping handler handle (a_resource: READABLE_STRING_8; f: WSF_ROUTER_MAPPING_FACTORY; rqst_methods: detachable WSF_REQUEST_METHODS) -- Map the mapping created by factory `f' for resource `a_resource'. + -- if `rqst_methods' is set, accept only request method in `rqst_methods'. + -- if `rqst_method' is Void, accept any request methods. require a_resource_attached: a_resource /= Void f_attached: f /= Void diff --git a/library/server/wsf/router/wsf_router_item.e b/library/server/wsf/router/wsf_router_item.e index 00467390..c385d3bc 100644 --- a/library/server/wsf/router/wsf_router_item.e +++ b/library/server/wsf/router/wsf_router_item.e @@ -16,19 +16,13 @@ inherit DEBUG_OUTPUT create - make, - make_with_request_methods + make feature {NONE} -- Initialization - make (m: like mapping) + make (m: like mapping; r: like request_methods) do mapping := m - end - - make_with_request_methods (m: like mapping; r: like request_methods) - do - make (m) set_request_methods (r) end @@ -71,7 +65,7 @@ invariant mapping_attached: mapping /= Void note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router_context/support/starts_with/helpers/wsf_starts_with_context_router_helper.e b/library/server/wsf/router_context/support/starts_with/helpers/wsf_starts_with_context_router_helper.e index 77f53f32..2c219aef 100644 --- a/library/server/wsf/router_context/support/starts_with/helpers/wsf_starts_with_context_router_helper.e +++ b/library/server/wsf/router_context/support/starts_with/helpers/wsf_starts_with_context_router_helper.e @@ -14,42 +14,46 @@ feature -- Access feature -- Mapping helper: starts_with - map_starts_with (a_uri: READABLE_STRING_8; h: WSF_STARTS_WITH_CONTEXT_HANDLER [C]) + map_starts_with (a_uri: READABLE_STRING_8; h: WSF_STARTS_WITH_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_uri_attached: a_uri /= Void h_attached: h /= Void do - map_starts_with_request_methods (a_uri, h, Void) + router.map (create {WSF_STARTS_WITH_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) end map_starts_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_STARTS_WITH_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `map_starts_with' [June-2015]" require a_uri_attached: a_uri /= Void h_attached: h /= Void do - router.map_with_request_methods (create {WSF_STARTS_WITH_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) + map_starts_with (a_uri, h, rqst_methods) end feature -- Mapping helper: starts_with agent - map_starts_with_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [start_path: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) + map_starts_with_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [start_path: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_uri_attached: a_uri /= Void proc_attached: proc /= Void do - map_starts_with_agent_with_request_methods (a_uri, proc, Void) + map_starts_with (a_uri, create {WSF_STARTS_WITH_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end map_starts_with_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [start_path: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `map_starts_with_agent' [June-2015]" require a_uri_attached: a_uri /= Void proc_attached: proc /= Void do - map_starts_with_request_methods (a_uri, create {WSF_STARTS_WITH_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) + map_starts_with_agent (a_uri, proc, rqst_methods) end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router_context/support/uri/helpers/wsf_uri_context_router_helper.e b/library/server/wsf/router_context/support/uri/helpers/wsf_uri_context_router_helper.e index 8d5baa5b..239beeba 100644 --- a/library/server/wsf/router_context/support/uri/helpers/wsf_uri_context_router_helper.e +++ b/library/server/wsf/router_context/support/uri/helpers/wsf_uri_context_router_helper.e @@ -14,42 +14,46 @@ feature -- Access feature -- Mapping helper: uri - map_uri (a_uri: READABLE_STRING_8; h: WSF_URI_CONTEXT_HANDLER [C]) + map_uri (a_uri: READABLE_STRING_8; h: WSF_URI_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_uri_attached: a_uri /= Void h_attached: h /= Void do - map_uri_with_request_methods (a_uri, h, Void) + router.map (create {WSF_URI_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) end map_uri_with_request_methods (a_uri: READABLE_STRING_8; h: WSF_URI_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `map_uri' [June-2015]" require a_uri_attached: a_uri /= Void h_attached: h /= Void do - router.map_with_request_methods (create {WSF_URI_CONTEXT_MAPPING [C]}.make (a_uri, h), rqst_methods) + map_uri (a_uri, h, rqst_methods) end feature -- Mapping helper: uri agent - map_uri_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) + map_uri_agent (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_uri_attached: a_uri /= Void proc_attached: proc /= Void do - map_uri_agent_with_request_methods (a_uri, proc, Void) + map_uri (a_uri, create {WSF_URI_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end map_uri_agent_with_request_methods (a_uri: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `map_uri_agent' [June-2015]" require a_uri_attached: a_uri /= Void proc_attached: proc /= Void do - map_uri_with_request_methods (a_uri, create {WSF_URI_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) + map_uri_agent (a_uri, proc, rqst_methods) end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/wsf/router_context/support/uri_template/helpers/wsf_uri_template_context_router_helper.e b/library/server/wsf/router_context/support/uri_template/helpers/wsf_uri_template_context_router_helper.e index e3969420..bf1c5d56 100644 --- a/library/server/wsf/router_context/support/uri_template/helpers/wsf_uri_template_context_router_helper.e +++ b/library/server/wsf/router_context/support/uri_template/helpers/wsf_uri_template_context_router_helper.e @@ -14,42 +14,46 @@ feature -- Access feature -- Mapping helper: uri - map_uri_template (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_CONTEXT_HANDLER [C]) + map_uri_template (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_tpl_attached: a_tpl /= Void h_attached: h /= Void do - map_uri_template_with_request_methods (a_tpl, h, Void) + router.map (create {WSF_URI_TEMPLATE_CONTEXT_MAPPING [C]}.make (a_tpl, h), rqst_methods) end map_uri_template_with_request_methods (a_tpl: READABLE_STRING_8; h: WSF_URI_TEMPLATE_CONTEXT_HANDLER [C]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `make_uri_template' [June/2015]" require a_tpl_attached: a_tpl /= Void h_attached: h /= Void do - router.map_with_request_methods (create {WSF_URI_TEMPLATE_CONTEXT_MAPPING [C]}.make (a_tpl, h), rqst_methods) + map_uri_template (a_tpl, h, rqst_methods) end feature -- Mapping helper: uri agent - map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) + map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) require a_tpl_attached: a_tpl /= Void proc_attached: proc /= Void do - map_uri_template_agent_with_request_methods (a_tpl, proc, Void) + map_uri_template (a_tpl, create {WSF_URI_TEMPLATE_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) end map_uri_template_agent_with_request_methods (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable WSF_REQUEST_METHODS) + obsolete + "Use directly `make_uri_template_agent' [June/2015]" require a_tpl_attached: a_tpl /= Void proc_attached: proc /= Void do - map_uri_template_with_request_methods (a_tpl, create {WSF_URI_TEMPLATE_AGENT_CONTEXT_HANDLER [C] }.make (proc), rqst_methods) + map_uri_template_agent (a_tpl, proc, rqst_methods) end note - copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software From 7d089a88c2ad6685d80a0caef145e0d3ec7505b4 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 11 Jun 2015 10:08:44 +0200 Subject: [PATCH 04/36] Made compilable without SSL enabled (i.e when variable named "httpd_ssl_disabled" is set to "true") --- .../src/httpd/configuration/httpd_configuration_i.e | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e index 93492678..33c796b1 100644 --- a/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e +++ b/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e @@ -200,43 +200,31 @@ feature -- SSL Helpers set_ssl_protocol_to_ssl_2_or_3 -- Set `ssl_protocol' with `Ssl_23'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Ssl_23 end set_ssl_protocol_to_ssl_3 -- Set `ssl_protocol' with `Ssl_3'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Ssl_3 end set_ssl_protocol_to_tls_1_0 -- Set `ssl_protocol' with `Tls_1_0'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_0 end set_ssl_protocol_to_tls_1_1 -- Set `ssl_protocol' with `Tls_1_1'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_1 end set_ssl_protocol_to_tls_1_2 -- Set `ssl_protocol' with `Tls_1_2'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Tls_1_2 end set_ssl_protocol_to_dtls_1_0 -- Set `ssl_protocol' with `Dtls_1_0'. deferred - ensure - ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.Dtls_1_0 end note From 0160ce05dde72a3cee07433a45073fe218f03235 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 12 Jun 2015 12:00:54 +0200 Subject: [PATCH 05/36] Updated wizard template ecf to take into account current limitation, or known issue related to libcurl and ssl. --- tools/estudio_wizard/rootdir/resources/${APP_NAME}.ecf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/estudio_wizard/rootdir/resources/${APP_NAME}.ecf b/tools/estudio_wizard/rootdir/resources/${APP_NAME}.ecf index 6562aee1..851addd9 100644 --- a/tools/estudio_wizard/rootdir/resources/${APP_NAME}.ecf +++ b/tools/estudio_wizard/rootdir/resources/${APP_NAME}.ecf @@ -27,6 +27,8 @@ {if condition="$WIZ.connectors.use_standalone ~ $WIZ_YES"} + + @@ -36,6 +38,7 @@ {if condition="$WIZ.connectors.use_nino ~ $WIZ_YES"} + @@ -45,6 +48,7 @@ {if condition="$WIZ.connectors.use_cgi ~ $WIZ_YES"} + @@ -54,6 +58,7 @@ {if condition="$WIZ.connectors.use_libfcgi ~ $WIZ_YES"} + From 9e336deb497d3fcf4db73bc117d72cb659f727f5 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 12 Jun 2015 12:43:54 +0200 Subject: [PATCH 06/36] Updated EWF estudio wizard. --- .../ewf_ise_console_wizard-safe.ecf | 24 +++++++++++++++++++ tools/estudio_wizard/ewf_ise_wizard-safe.ecf | 21 ---------------- tools/estudio_wizard/install_ise_wizard.bat | 2 +- tools/estudio_wizard/install_ise_wizard.sh | 2 +- tools/install_ewf.bat | 10 +++++++- tools/uninstall_ewf.bat | 3 +++ 6 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf diff --git a/tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf b/tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf new file mode 100644 index 00000000..5e4b1450 --- /dev/null +++ b/tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf @@ -0,0 +1,24 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + /gui$ + /lib$ + + + + diff --git a/tools/estudio_wizard/ewf_ise_wizard-safe.ecf b/tools/estudio_wizard/ewf_ise_wizard-safe.ecf index 2c3cc9ae..6b399757 100644 --- a/tools/estudio_wizard/ewf_ise_wizard-safe.ecf +++ b/tools/estudio_wizard/ewf_ise_wizard-safe.ecf @@ -1,27 +1,6 @@ - - - /.git$ - /EIFGENs$ - /.svn$ - - - - - - - - - - /gui$ - /lib$ - - - - /.git$ diff --git a/tools/estudio_wizard/install_ise_wizard.bat b/tools/estudio_wizard/install_ise_wizard.bat index ca06d95a..1172efde 100644 --- a/tools/estudio_wizard/install_ise_wizard.bat +++ b/tools/estudio_wizard/install_ise_wizard.bat @@ -1,7 +1,7 @@ setlocal set TMP_ROOTDIR=%~dp0rootdir -set TMP_TARGETNAME=gui_wizard +set TMP_TARGETNAME=wizard set WIZ_TARGET=%ISE_EIFFEL%\studio\wizards\new_projects\ewf rd /q/s %WIZ_TARGET% diff --git a/tools/estudio_wizard/install_ise_wizard.sh b/tools/estudio_wizard/install_ise_wizard.sh index ab64d020..9b5496ea 100644 --- a/tools/estudio_wizard/install_ise_wizard.sh +++ b/tools/estudio_wizard/install_ise_wizard.sh @@ -1,7 +1,7 @@ #!/bin/sh mkdir tmp -ecb -config ewf_ise_wizard-safe.ecf -target gui_wizard -finalize -c_compile -project_path tmp +ecb -config ewf_ise_wizard-safe.ecf -target wizard -finalize -c_compile -project_path tmp mkdir -p spec/$ISE_PLATFORM mv tmp/EIFGENs/wizard/F_code/wizard spec/$ISE_PLATFORM/wizard rm -rf tmp diff --git a/tools/install_ewf.bat b/tools/install_ewf.bat index ff75cdc2..8d345df9 100644 --- a/tools/install_ewf.bat +++ b/tools/install_ewf.bat @@ -64,7 +64,6 @@ echo Install library: ewf/wsf_html echo Install library: ewf/encoder %COPYCMD% %TMP_DIR%\library\text\encoder %TMP_CONTRIB_DIR%\library\web\framework\ewf\text\encoder - echo Install library: ewf/obsolete %COPYCMD% %TMP_DIR%\library\server\obsolete %TMP_CONTRIB_DIR%\library\web\framework\ewf\obsolete @@ -74,6 +73,15 @@ echo Install examples %COPYCMD% %TMP_DIR%\examples %TMP_CONTRIB_DIR%\examples\web\ewf %COPYCMD% %TMP_DIR%\precomp %TMP_CONTRIB_DIR%\examples\web\ewf_precomp +echo Install EWF wizard +%COPYCMD% %TMP_DIR%\tools\estudio_wizard %TMP_TARGET_DIR%\help\wizards\ewf +rename %TMP_TARGET_DIR%\help\wizards\ewf\install_ise_wizard.bat %TMP_TARGET_DIR%\help\wizards\ewf\install.bat +rename %TMP_TARGET_DIR%\help\wizards\ewf\install_ise_wizard.sh %TMP_TARGET_DIR%\help\wizards\ewf\install.sh +rename %TMP_TARGET_DIR%\help\wizards\ewf\ewf_ise_wizard-safe.ecf %TMP_TARGET_DIR%\help\wizards\ewf\wizard.ecf +rename %TMP_TARGET_DIR%\help\wizards\ewf\ewf_ise_console_wizard-safe.ecf %TMP_TARGET_DIR%\help\wizards\ewf\console_wizard.ecf +%SAFE_MD% %TMP_TARGET_DIR%\help\wizards\ewf\rootdir\pixmaps +%SAFE_MD% %TMP_TARGET_DIR%\help\wizards\ewf\rootdir\templates + echo Install library: error %COPYCMD% %TMP_DIR%\library\utility\general\error %TMP_CONTRIB_DIR%\library\utility\general\error echo Install library: http_client diff --git a/tools/uninstall_ewf.bat b/tools/uninstall_ewf.bat index c0b09777..6a3d2b86 100644 --- a/tools/uninstall_ewf.bat +++ b/tools/uninstall_ewf.bat @@ -48,6 +48,9 @@ echo Uninstall ewf examples %RDCMD% %TMP_CONTRIB_DIR%\examples\web\ewf %RDCMD% %TMP_CONTRIB_DIR%\examples\ewb\ewf_precomp +echo Uninstall ewf wizard +%RDCMD% %TMP_TARGET_DIR%\help\wizards\ewf + echo Uninstall library: error %RDCMD% %TMP_CONTRIB_DIR%\library\utility\general\error echo Uninstall library: http_client From c2d3ea6138782f086d789e42dd3d5ef11262c21c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 12 Jun 2015 12:56:46 +0200 Subject: [PATCH 07/36] Simplified file names, and harmonized with estudio wizards. --- .../{ewf_ise_console_wizard-safe.ecf => console_wizard.ecf} | 0 tools/estudio_wizard/install_ise_wizard.bat | 2 +- tools/estudio_wizard/install_ise_wizard.sh | 2 +- tools/estudio_wizard/{ewf_ise_wizard-safe.ecf => wizard.ecf} | 0 tools/install_ewf.bat | 2 -- 5 files changed, 2 insertions(+), 4 deletions(-) rename tools/estudio_wizard/{ewf_ise_console_wizard-safe.ecf => console_wizard.ecf} (100%) rename tools/estudio_wizard/{ewf_ise_wizard-safe.ecf => wizard.ecf} (100%) diff --git a/tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf b/tools/estudio_wizard/console_wizard.ecf similarity index 100% rename from tools/estudio_wizard/ewf_ise_console_wizard-safe.ecf rename to tools/estudio_wizard/console_wizard.ecf diff --git a/tools/estudio_wizard/install_ise_wizard.bat b/tools/estudio_wizard/install_ise_wizard.bat index 1172efde..d70071f7 100644 --- a/tools/estudio_wizard/install_ise_wizard.bat +++ b/tools/estudio_wizard/install_ise_wizard.bat @@ -12,7 +12,7 @@ move %WIZ_TARGET%\ewf.dsc %WIZ_TARGET%\..\ewf.dsc rd /q/s tmp mkdir tmp -ecb -config ewf_ise_wizard-safe.ecf -target %TMP_TARGETNAME% -finalize -c_compile -project_path tmp +ecb -config wizard.ecf -target %TMP_TARGETNAME% -finalize -c_compile -project_path tmp rd /q/s %WIZ_TARGET%\spec mkdir %WIZ_TARGET%\spec mkdir %WIZ_TARGET%\spec\%ISE_PLATFORM% diff --git a/tools/estudio_wizard/install_ise_wizard.sh b/tools/estudio_wizard/install_ise_wizard.sh index 9b5496ea..23fca6a5 100644 --- a/tools/estudio_wizard/install_ise_wizard.sh +++ b/tools/estudio_wizard/install_ise_wizard.sh @@ -1,7 +1,7 @@ #!/bin/sh mkdir tmp -ecb -config ewf_ise_wizard-safe.ecf -target wizard -finalize -c_compile -project_path tmp +ecb -config wizard.ecf -target wizard -finalize -c_compile -project_path tmp mkdir -p spec/$ISE_PLATFORM mv tmp/EIFGENs/wizard/F_code/wizard spec/$ISE_PLATFORM/wizard rm -rf tmp diff --git a/tools/estudio_wizard/ewf_ise_wizard-safe.ecf b/tools/estudio_wizard/wizard.ecf similarity index 100% rename from tools/estudio_wizard/ewf_ise_wizard-safe.ecf rename to tools/estudio_wizard/wizard.ecf diff --git a/tools/install_ewf.bat b/tools/install_ewf.bat index 8d345df9..403d95b1 100644 --- a/tools/install_ewf.bat +++ b/tools/install_ewf.bat @@ -77,8 +77,6 @@ echo Install EWF wizard %COPYCMD% %TMP_DIR%\tools\estudio_wizard %TMP_TARGET_DIR%\help\wizards\ewf rename %TMP_TARGET_DIR%\help\wizards\ewf\install_ise_wizard.bat %TMP_TARGET_DIR%\help\wizards\ewf\install.bat rename %TMP_TARGET_DIR%\help\wizards\ewf\install_ise_wizard.sh %TMP_TARGET_DIR%\help\wizards\ewf\install.sh -rename %TMP_TARGET_DIR%\help\wizards\ewf\ewf_ise_wizard-safe.ecf %TMP_TARGET_DIR%\help\wizards\ewf\wizard.ecf -rename %TMP_TARGET_DIR%\help\wizards\ewf\ewf_ise_console_wizard-safe.ecf %TMP_TARGET_DIR%\help\wizards\ewf\console_wizard.ecf %SAFE_MD% %TMP_TARGET_DIR%\help\wizards\ewf\rootdir\pixmaps %SAFE_MD% %TMP_TARGET_DIR%\help\wizards\ewf\rootdir\templates From 8992dbc515de5719b46d7dce585c9ae165509b7e Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 12 Jun 2015 19:01:35 +0200 Subject: [PATCH 08/36] Added wsf_html in the obsolete v0 folder. mostly because it is also dependent on "wsf", so it has to be using the obsolete v0 ecf. --- .../obsolete/v0/wsf_html/wsf_html-safe.ecf | 21 +++++++++++++++++++ .../server/obsolete/v0/wsf_html/wsf_html.ecf | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf create mode 100644 library/server/obsolete/v0/wsf_html/wsf_html.ecf diff --git a/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf new file mode 100644 index 00000000..93e40265 --- /dev/null +++ b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf @@ -0,0 +1,21 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + + + diff --git a/library/server/obsolete/v0/wsf_html/wsf_html.ecf b/library/server/obsolete/v0/wsf_html/wsf_html.ecf new file mode 100644 index 00000000..db477689 --- /dev/null +++ b/library/server/obsolete/v0/wsf_html/wsf_html.ecf @@ -0,0 +1,21 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + + + From 7bea163f4683f3cb9edde85998605f0ced0357d6 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Sun, 14 Jun 2015 21:34:41 +0200 Subject: [PATCH 09/36] Updated ecf from obsolete v0 folder to include the "_v0" suffix in the library names. --- .../obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf | 4 ++-- .../server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf | 4 ++-- .../server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf | 4 ++-- library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf | 4 ++-- library/server/obsolete/v0/ewsgi/ewsgi-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/connector/libfcgi.ecf | 4 ++-- library/server/obsolete/v0/wsf/connector/nino-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/connector/nino.ecf | 4 ++-- library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/default/libfcgi.ecf | 4 ++-- library/server/obsolete/v0/wsf/default/nino-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/default/nino.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_extension-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_extension.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_policy_driven.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf/wsf_router_context.ecf | 4 ++-- library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf | 4 ++-- library/server/obsolete/v0/wsf_html/wsf_html.ecf | 4 ++-- 22 files changed, 44 insertions(+), 44 deletions(-) diff --git a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf index 0178aae0..62f9065a 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf index c4196cfd..7f3368d1 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf b/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf index bfcccf72..18ca2208 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf b/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf index 25198b63..8e222c2a 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/ewsgi/ewsgi-safe.ecf b/library/server/obsolete/v0/ewsgi/ewsgi-safe.ecf index e1401dba..8b2211af 100644 --- a/library/server/obsolete/v0/ewsgi/ewsgi-safe.ecf +++ b/library/server/obsolete/v0/ewsgi/ewsgi-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf b/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf index 68612d66..f82815de 100644 --- a/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/connector/libfcgi.ecf b/library/server/obsolete/v0/wsf/connector/libfcgi.ecf index 664ecbd6..7fbaa9c4 100644 --- a/library/server/obsolete/v0/wsf/connector/libfcgi.ecf +++ b/library/server/obsolete/v0/wsf/connector/libfcgi.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/connector/nino-safe.ecf b/library/server/obsolete/v0/wsf/connector/nino-safe.ecf index 359d8833..3538c5f8 100644 --- a/library/server/obsolete/v0/wsf/connector/nino-safe.ecf +++ b/library/server/obsolete/v0/wsf/connector/nino-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/connector/nino.ecf b/library/server/obsolete/v0/wsf/connector/nino.ecf index 40913165..069bd8d0 100644 --- a/library/server/obsolete/v0/wsf/connector/nino.ecf +++ b/library/server/obsolete/v0/wsf/connector/nino.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf b/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf index 24a3a7fe..2e137baa 100644 --- a/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/default/libfcgi.ecf b/library/server/obsolete/v0/wsf/default/libfcgi.ecf index c35cd504..dfe174d5 100644 --- a/library/server/obsolete/v0/wsf/default/libfcgi.ecf +++ b/library/server/obsolete/v0/wsf/default/libfcgi.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/default/nino-safe.ecf b/library/server/obsolete/v0/wsf/default/nino-safe.ecf index f9f0aa19..6bad0d3f 100644 --- a/library/server/obsolete/v0/wsf/default/nino-safe.ecf +++ b/library/server/obsolete/v0/wsf/default/nino-safe.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/default/nino.ecf b/library/server/obsolete/v0/wsf/default/nino.ecf index 0157a5a6..0530a122 100644 --- a/library/server/obsolete/v0/wsf/default/nino.ecf +++ b/library/server/obsolete/v0/wsf/default/nino.ecf @@ -1,6 +1,6 @@ - - + + /EIFGENs$ diff --git a/library/server/obsolete/v0/wsf/wsf-safe.ecf b/library/server/obsolete/v0/wsf/wsf-safe.ecf index edd519f2..e51a2755 100644 --- a/library/server/obsolete/v0/wsf/wsf-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf-safe.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf b/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf index 433868dc..e488c587 100644 --- a/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_extension.ecf b/library/server/obsolete/v0/wsf/wsf_extension.ecf index 65fe0016..f6370e83 100644 --- a/library/server/obsolete/v0/wsf/wsf_extension.ecf +++ b/library/server/obsolete/v0/wsf/wsf_extension.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf b/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf index d42de944..70e8e2ea 100644 --- a/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf b/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf index ae8e48d8..347334fc 100644 --- a/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf +++ b/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf b/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf index f55c41ed..f56451af 100644 --- a/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf/wsf_router_context.ecf b/library/server/obsolete/v0/wsf/wsf_router_context.ecf index ba8138f4..5edfb081 100644 --- a/library/server/obsolete/v0/wsf/wsf_router_context.ecf +++ b/library/server/obsolete/v0/wsf/wsf_router_context.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf index 93e40265..c347aae5 100644 --- a/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf +++ b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf @@ -1,6 +1,6 @@ - - + + /.git$ diff --git a/library/server/obsolete/v0/wsf_html/wsf_html.ecf b/library/server/obsolete/v0/wsf_html/wsf_html.ecf index db477689..020415fa 100644 --- a/library/server/obsolete/v0/wsf_html/wsf_html.ecf +++ b/library/server/obsolete/v0/wsf_html/wsf_html.ecf @@ -1,6 +1,6 @@ - - + + /.git$ From c0d5b7c9688c4c8b649ce738f73cfa3d0c886f37 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 16 Jun 2015 15:02:17 +0200 Subject: [PATCH 10/36] Added make_from_execution procedure to ease implementing various use cases. --- .../ewsgi/specification/connector/wgi_execution.e | 7 +++++++ library/server/wsf/src/wsf_execution.e | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/library/server/ewsgi/specification/connector/wgi_execution.e b/library/server/ewsgi/specification/connector/wgi_execution.e index 07070ea0..d74f4ad1 100644 --- a/library/server/ewsgi/specification/connector/wgi_execution.e +++ b/library/server/ewsgi/specification/connector/wgi_execution.e @@ -18,6 +18,13 @@ feature {NONE} -- Initialization response := res end + frozen make_from_execution (a_execution: WGI_EXECUTION) + -- Create current execution from `a_execution'. + do + request := a_execution.request + response := a_execution.response + end + feature {WGI_EXECUTION} -- Access request: WGI_REQUEST diff --git a/library/server/wsf/src/wsf_execution.e b/library/server/wsf/src/wsf_execution.e index 0f0ddb5f..8bc0a978 100644 --- a/library/server/wsf/src/wsf_execution.e +++ b/library/server/wsf/src/wsf_execution.e @@ -10,7 +10,8 @@ inherit WGI_EXECUTION rename request as wgi_request, - response as wgi_response + response as wgi_response, + make_from_execution as make_from_wgi_execution redefine make, execute, @@ -23,7 +24,7 @@ inherit feature {NONE} -- Initialization - make (req: WGI_REQUEST; res: WGI_RESPONSE) + frozen make (req: WGI_REQUEST; res: WGI_RESPONSE) -- Create Current execution with request `req' and response `res'. do Precursor (req, res) @@ -32,6 +33,15 @@ feature {NONE} -- Initialization initialize end + frozen make_from_execution (a_execution: WSF_EXECUTION) + -- Create current execution from `a_execution'. + do + make_from_wgi_execution (a_execution) + request := a_execution.request + response := a_execution.response + initialize + end + initialize -- Initialize Current object. --| To be redefined if needed. From 80709578d64f29dfb9cb4b9fc07cae5a1a3e69ac Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 16 Jun 2015 20:34:57 +0200 Subject: [PATCH 11/36] Updated workbook Eiffel code to follow new EWF concurrent design. --- doc/workbook/basics/simple/application.e | 17 +- .../basics/simple/application_execution.e | 26 ++ doc/workbook/basics/simple_html/application.e | 57 +--- .../simple_html/application_execution.e | 66 ++++ .../generating_response/exel/application.e | 27 +- .../exel/application_execution.e | 36 +++ .../generating_response/headers/application.e | 48 +-- .../headers/application_execution.e | 57 ++++ .../generating_response/search/application.e | 163 +--------- .../search/application_execution.e | 172 ++++++++++ .../generating_response/status/application.e | 129 +------- .../status/application_execution.e | 138 ++++++++ .../handling_cookies/example/application.e | 133 +------- .../example/application_execution.e | 141 ++++++++ .../handling_request/form/get/application.e | 92 +----- .../form/get/application_execution.e | 101 ++++++ .../handling_request/form/post/application.e | 74 +---- .../form/post/application_execution.e | 83 +++++ .../headers/browser_name/application.e | 89 +---- .../browser_name/application_execution.e | 97 ++++++ .../headers/cgi_variables/application.e | 295 +---------------- .../cgi_variables/application_execution.e | 303 ++++++++++++++++++ .../headers/header_fields/application.e | 97 +----- .../header_fields/application_execution.e | 105 ++++++ .../upload_file/application.e | 49 +-- .../upload_file/application_execution.e | 58 ++++ 26 files changed, 1409 insertions(+), 1244 deletions(-) create mode 100644 doc/workbook/basics/simple/application_execution.e create mode 100644 doc/workbook/basics/simple_html/application_execution.e create mode 100644 doc/workbook/generating_response/exel/application_execution.e create mode 100644 doc/workbook/generating_response/headers/application_execution.e create mode 100644 doc/workbook/generating_response/search/application_execution.e create mode 100644 doc/workbook/generating_response/status/application_execution.e create mode 100644 doc/workbook/handling_cookies/example/application_execution.e create mode 100644 doc/workbook/handling_request/form/get/application_execution.e create mode 100644 doc/workbook/handling_request/form/post/application_execution.e create mode 100644 doc/workbook/handling_request/headers/browser_name/application_execution.e create mode 100644 doc/workbook/handling_request/headers/cgi_variables/application_execution.e create mode 100644 doc/workbook/handling_request/headers/header_fields/application_execution.e create mode 100644 doc/workbook/handling_request/upload_file/application_execution.e diff --git a/doc/workbook/basics/simple/application.e b/doc/workbook/basics/simple/application.e index 76fc8322..cf939f60 100644 --- a/doc/workbook/basics/simple/application.e +++ b/doc/workbook/basics/simple/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that Generates Plain Text" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,15 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - do - -- To send a response we need to setup, the status code and - -- the response headers. - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) - res.put_string ("Hello World") - end - end diff --git a/doc/workbook/basics/simple/application_execution.e b/doc/workbook/basics/simple/application_execution.e new file mode 100644 index 00000000..28b1e2f3 --- /dev/null +++ b/doc/workbook/basics/simple/application_execution.e @@ -0,0 +1,26 @@ +note + description : "Basic Service that Generates Plain Text" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + do + -- To send a response we need to setup, the status code and + -- the response headers. + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) + response.put_string ("Hello World") + end + +end diff --git a/doc/workbook/basics/simple_html/application.e b/doc/workbook/basics/simple_html/application.e index 77b1b02c..cf939f60 100644 --- a/doc/workbook/basics/simple_html/application.e +++ b/doc/workbook/basics/simple_html/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that Generate HTML" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,55 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - do - -- To send a response we need to setup, the status code and - -- the response headers. - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) - res.put_string (web_page) - end - - - web_page: STRING = "[ - - - - Resume - - - -
-
-

Objective

-

To take a position as a software engineer.

-

Experience

-

Junior Developer, Software Company (2010 - Present)

-
    -
  • Designed and implemented end-user features for Flagship Product
  • -
  • Wrote third-party JavaScript and Eiffel libraries
  • -
-

Skills

-

Languages: C#, JavaScript, Python, Ruby, Eiffel

-

Frameworks: .NET, Node.js, Django, Ruby on Rails, EWF

-

Education

-

BS, Economics, My University

-
    -
  • Award for best senior thesis
  • -
  • GPA: 3.8
  • -
-
- - - -]" - - end diff --git a/doc/workbook/basics/simple_html/application_execution.e b/doc/workbook/basics/simple_html/application_execution.e new file mode 100644 index 00000000..63204435 --- /dev/null +++ b/doc/workbook/basics/simple_html/application_execution.e @@ -0,0 +1,66 @@ +note + description : "Basic Service that Generate HTML" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + do + -- To send a response we need to setup, the status code and + -- the response headers. + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) + response.put_string (web_page) + end + + + web_page: STRING = "[ + + + + Resume + + + +
+
+

Objective

+

To take a position as a software engineer.

+

Experience

+

Junior Developer, Software Company (2010 - Present)

+
    +
  • Designed and implemented end-user features for Flagship Product
  • +
  • Wrote third-party JavaScript and Eiffel libraries
  • +
+

Skills

+

Languages: C#, JavaScript, Python, Ruby, Eiffel

+

Frameworks: .NET, Node.js, Django, Ruby on Rails, EWF

+

Education

+

BS, Economics, My University

+
    +
  • Award for best senior thesis
  • +
  • GPA: 3.8
  • +
+
+ + + +]" + + +end diff --git a/doc/workbook/generating_response/exel/application.e b/doc/workbook/generating_response/exel/application.e index ffd55d2b..cf939f60 100644 --- a/doc/workbook/generating_response/exel/application.e +++ b/doc/workbook/generating_response/exel/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that show how to use common Status Code" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,25 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - do - -- To send a response we need to setup, the status code and - -- the response headers. - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/csv"],["Content-Disposition","attachment;filename=Report.xls"],["Content-Length", sheet.count.out]>>) - res.put_string (sheet) - end - - -- ,["Content-Disposition","attachment;filename=Report.xls"] - - - sheet: STRING ="[ - Q1 Q2 Q3 Q4 Total -Cherries 78 87 92 29 =SUM(B2:E2) -Grapes 77 86 93 30 =SUM(B3:E3) - ]" - - end diff --git a/doc/workbook/generating_response/exel/application_execution.e b/doc/workbook/generating_response/exel/application_execution.e new file mode 100644 index 00000000..3c93fb5a --- /dev/null +++ b/doc/workbook/generating_response/exel/application_execution.e @@ -0,0 +1,36 @@ +note + description : "Basic Service that show how to use common Status Code" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + do + -- To send a response we need to setup, the status code and + -- the response headers. + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/csv"],["Content-Disposition","attachment;filename=Report.xls"],["Content-Length", sheet.count.out]>>) + response.put_string (sheet) + end + + -- ,["Content-Disposition","attachment;filename=Report.xls"] + + + sheet: STRING ="[ + Q1 Q2 Q3 Q4 Total +Cherries 78 87 92 29 =SUM(B2:E2) +Grapes 77 86 93 30 =SUM(B3:E3) + ]" + + +end diff --git a/doc/workbook/generating_response/headers/application.e b/doc/workbook/generating_response/headers/application.e index 6e28c660..cf939f60 100644 --- a/doc/workbook/generating_response/headers/application.e +++ b/doc/workbook/generating_response/headers/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that build a generic front end for the most used search engines." - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,46 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_message: STRING - do - -- (1) To send a response we need to setup, the status code and the response headers. --- res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) --- res.put_string (web_page) - - -- (2) Using put_header_line --- res.set_status_code ({HTTP_STATUS_CODE}.ok) --- res.put_header_line ("Content-Type:text/html") - res.put_header_line ("Content-Length:"+ web_page.count.out) - res.put_header_line ("Content-Type:text/plain") - - res.put_string (web_page) - end - - - -feature -- Home Page - - web_page: STRING = "[ - - - - EWF Headers Responses - - -
-

Example Header Response

-

Response headers

- -
- - - -]" end diff --git a/doc/workbook/generating_response/headers/application_execution.e b/doc/workbook/generating_response/headers/application_execution.e new file mode 100644 index 00000000..5b042d53 --- /dev/null +++ b/doc/workbook/generating_response/headers/application_execution.e @@ -0,0 +1,57 @@ +note + description : "Basic Service that build a generic front end for the most used search engines." + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_message: STRING + do + -- (1) To send a response we need to setup, the status code and the response headers. +-- response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) +-- response.put_string (web_page) + + -- (2) Using put_header_line +-- response.set_status_code ({HTTP_STATUS_CODE}.ok) +-- response.put_header_line ("Content-Type:text/html") + response.put_header_line ("Content-Length:"+ web_page.count.out) + response.put_header_line ("Content-Type:text/plain") + + response.put_string (web_page) + end + + + +feature -- Home Page + + web_page: STRING = "[ + + + + EWF Headers Responses + + +
+

Example Header Response

+

Response headers

+ +
+ + + +]" +end diff --git a/doc/workbook/generating_response/search/application.e b/doc/workbook/generating_response/search/application.e index 60a85660..cf939f60 100644 --- a/doc/workbook/generating_response/search/application.e +++ b/doc/workbook/generating_response/search/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that build a generic front end for the most used search engines." - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,161 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_message: STRING - do - -- To send a response we need to setup, the status code and - -- the response headers. - if req.is_get_request_method then - if req.path_info.same_string ("/") then - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) - res.put_string (web_page) - else - send_resouce_not_found (req, res) - end - elseif req.is_post_request_method then - if req.path_info.same_string ("/search") then - if attached {WSF_STRING} req.form_parameter ("query") as l_query then - if attached {WSF_STRING} req.form_parameter ("engine") as l_engine then - if attached {STRING} map.at (l_engine.value) as l_engine_url then - l_engine_url.append (l_query.value) - send_redirect (req, res, l_engine_url) - -- res.redirect_now (l_engine_url) - else - send_bad_request (req, res, " search engine: " + l_engine.value + " not supported,
try with Google or Bing") - end - else - send_bad_request (req, res, " search engine not selected") - end - else - send_bad_request (req, res, " form_parameter query is not present") - end - else - send_resouce_not_found (req, res) - end - else - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Method Not Allowed") - l_message.replace_substring_all ("$status", "Method Not Allowed 405") - -- Method not allowed - res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - end - end - - -feature -- Engine Map - - map : STRING_TABLE[STRING] - do - create Result.make (2) - Result.put ("http://www.google.com/search?q=", "Google") - Result.put ("http://www.bing.com/search?q=", "Bing") - end - -feature -- Redirect - - send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32) - -- Redirect to `a_location' - local - h: HTTP_HEADER - do - create h.make - h.put_content_type_text_html - h.put_current_date - h.put_location (a_location) - res.set_status_code ({HTTP_STATUS_CODE}.see_other) - res.put_header_text (h.string) - end - -feature -- Bad Request - - send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE; description: STRING) - local - l_message: STRING - do - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Bad Request") - l_message.replace_substring_all ("$status", "Bad Request" + description) - res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - end - -feature -- Resource not found - - send_resouce_not_found (req: WSF_REQUEST; res: WSF_RESPONSE) - local - l_message: STRING - do - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Resource not found") - l_message.replace_substring_all ("$status", "Resource " + req.request_uri + " not found 404") - res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - end - -feature -- Home Page - - web_page: STRING = "[ - - - - Generic Search Engine - - -
-

Generic Search Engine

-
-
- Search:
-
- -
- -
- -

-
- -
- - -
- - - -]" - -feature -- Generic Message - - message_template: STRING="[ - - - - $title - - - -
-
-

This page is an example of $status

- - - - -]" - - - - end diff --git a/doc/workbook/generating_response/search/application_execution.e b/doc/workbook/generating_response/search/application_execution.e new file mode 100644 index 00000000..1e3ebe08 --- /dev/null +++ b/doc/workbook/generating_response/search/application_execution.e @@ -0,0 +1,172 @@ +note + description : "Basic Service that build a generic front end for the most used search engines." + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_message: STRING + do + -- To send a response we need to setup, the status code and + -- the response headers. + if request.is_get_request_method then + if request.path_info.same_string ("/") then + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) + response.put_string (web_page) + else + send_resouce_not_found (request, response) + end + elseif request.is_post_request_method then + if request.path_info.same_string ("/search") then + if attached {WSF_STRING} request.form_parameter ("query") as l_query then + if attached {WSF_STRING} request.form_parameter ("engine") as l_engine then + if attached {STRING} map.at (l_engine.value) as l_engine_url then + l_engine_url.append (l_query.value) + send_redirect (request, response, l_engine_url) + -- response.redirect_now (l_engine_url) + else + send_bad_request (request, response, " search engine: " + l_engine.value + " not supported,
try with Google or Bing") + end + else + send_bad_request (request, response, " search engine not selected") + end + else + send_bad_request (request, response, " form_parameter query is not present") + end + else + send_resouce_not_found (request, response) + end + else + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Method Not Allowed") + l_message.replace_substring_all ("$status", "Method Not Allowed 405") + -- Method not allowed + response.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + response.put_string (l_message) + end + end + + +feature -- Engine Map + + map : STRING_TABLE[STRING] + do + create Result.make (2) + Result.put ("http://www.google.com/search?q=", "Google") + Result.put ("http://www.bing.com/search?q=", "Bing") + end + +feature -- Redirect + + send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32) + -- Redirect to `a_location' + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_html + h.put_current_date + h.put_location (a_location) + res.set_status_code ({HTTP_STATUS_CODE}.see_other) + res.put_header_text (h.string) + end + +feature -- Bad Request + + send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE; description: STRING) + local + l_message: STRING + do + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Bad Request") + l_message.replace_substring_all ("$status", "Bad Request" + description) + res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + res.put_string (l_message) + end + +feature -- Resource not found + + send_resouce_not_found (req: WSF_REQUEST; res: WSF_RESPONSE) + local + l_message: STRING + do + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Resource not found") + l_message.replace_substring_all ("$status", "Resource " + req.request_uri + " not found 404") + res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + res.put_string (l_message) + end + +feature -- Home Page + + web_page: STRING = "[ + + + + Generic Search Engine + + +
+

Generic Search Engine

+
+
+ Search:
+
+ +
+ +
+ +

+
+ +
+ + +
+ + + +]" + +feature -- Generic Message + + message_template: STRING="[ + + + + $title + + + +
+
+

This page is an example of $status

+ + + + +]" + + + + +end diff --git a/doc/workbook/generating_response/status/application.e b/doc/workbook/generating_response/status/application.e index 7aa03ac9..cf939f60 100644 --- a/doc/workbook/generating_response/status/application.e +++ b/doc/workbook/generating_response/status/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that a simple web page to show the most common status codes" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,127 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_message: STRING - do - -- To send a response we need to setup, the status code and - -- the response headers. - if req.is_get_request_method then - if req.path_info.same_string ("/") then - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) - res.put_string (web_page) - elseif req.path_info.same_string ("/redirect") then - send_redirect (req, res, "https://httpwg.github.io/") - elseif req.path_info.same_string ("/bad_request") then - -- Here you can do some logic for example log, send emails to register the error, before to send the response. - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Bad Request") - l_message.replace_substring_all ("$status", "Bad Request 400") - res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - elseif req.path_info.same_string ("/internal_error") then - -- Here you can do some logic for example log, send emails to register the error, before to send the response. - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Internal Server Error") - l_message.replace_substring_all ("$status", "Internal Server Error 500") - res.put_header ({HTTP_STATUS_CODE}.internal_server_error, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - else - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Resource not found") - l_message.replace_substring_all ("$status", "Resource not found 400") - res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - end - else - create l_message.make_from_string (message_template) - l_message.replace_substring_all ("$title", "Method Not Allowed") - l_message.replace_substring_all ("$status", "Method Not Allowed 405") - -- Method not allowed - res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) - res.put_string (l_message) - end - end - - -feature -- Home Page - - send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32) - -- Redirect to `a_location' - local - h: HTTP_HEADER - do - create h.make - h.put_content_type_text_html - h.put_current_date - h.put_location (a_location) - res.set_status_code ({HTTP_STATUS_CODE}.see_other) - res.put_header_text (h.string) - end - - web_page: STRING = "[ - - - - Example showing common status codes - - - -
-
-

This page is an example of Status Code 200

- -

Redirect Example

-

Click on the following link will redirect you to the HTTP Specifcation, we can do the redirect from the HTML directly but - here we want to show you an exmaple, where you can do something before to send a redirect Redirect

- -

Bad Request

-

Click on the following link, the server will answer with a 400 error, check the status code Bad Request

- -

Internal Server Error

-

Click on the following link, the server will answer with a 500 error, check the status code Internal Error

- -

Resource not found

-

Click on the following link or add to the end of the url something like /1030303 the server will answer with a 404 error, check the status code Not found

- -
- - - -]" - -feature -- Generic Message - - message_template: STRING="[ - - - - $title - - - -
-
-

This page is an example of $status

- - - - -]" - - - - end diff --git a/doc/workbook/generating_response/status/application_execution.e b/doc/workbook/generating_response/status/application_execution.e new file mode 100644 index 00000000..691513b6 --- /dev/null +++ b/doc/workbook/generating_response/status/application_execution.e @@ -0,0 +1,138 @@ +note + description : "Basic Service that a simple web page to show the most common status codes" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_message: STRING + do + -- To send a response we need to setup, the status code and + -- the response headers. + if request.is_get_request_method then + if request.path_info.same_string ("/") then + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) + response.put_string (web_page) + elseif request.path_info.same_string ("/redirect") then + send_redirect (request, response, "https://httpwg.github.io/") + elseif request.path_info.same_string ("/bad_request") then + -- Here you can do some logic for example log, send emails to register the error, before to send the response. + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Bad Request") + l_message.replace_substring_all ("$status", "Bad Request 400") + response.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + response.put_string (l_message) + elseif request.path_info.same_string ("/internal_error") then + -- Here you can do some logic for example log, send emails to register the error, before to send the response. + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Internal Server Error") + l_message.replace_substring_all ("$status", "Internal Server Error 500") + response.put_header ({HTTP_STATUS_CODE}.internal_server_error, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + response.put_string (l_message) + else + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Resource not found") + l_message.replace_substring_all ("$status", "Resource not found 400") + response.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + response.put_string (l_message) + end + else + create l_message.make_from_string (message_template) + l_message.replace_substring_all ("$title", "Method Not Allowed") + l_message.replace_substring_all ("$status", "Method Not Allowed 405") + -- Method not allowed + response.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>) + response.put_string (l_message) + end + end + + +feature -- Home Page + + send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32) + -- Redirect to `a_location' + local + h: HTTP_HEADER + do + create h.make + h.put_content_type_text_html + h.put_current_date + h.put_location (a_location) + res.set_status_code ({HTTP_STATUS_CODE}.see_other) + res.put_header_text (h.string) + end + + web_page: STRING = "[ + + + + Example showing common status codes + + + +
+
+

This page is an example of Status Code 200

+ +

Redirect Example

+

Click on the following link will redirect you to the HTTP Specifcation, we can do the redirect from the HTML directly but + here we want to show you an exmaple, where you can do something before to send a redirect Redirect

+ +

Bad Request

+

Click on the following link, the server will answer with a 400 error, check the status code Bad Request

+ +

Internal Server Error

+

Click on the following link, the server will answer with a 500 error, check the status code Internal Error

+ +

Resource not found

+

Click on the following link or add to the end of the url something like /1030303 the server will answer with a 404 error, check the status code Not found

+ +
+ + + +]" + +feature -- Generic Message + + message_template: STRING="[ + + + + $title + + + +
+
+

This page is an example of $status

+ + + + +]" + + + + +end diff --git a/doc/workbook/handling_cookies/example/application.e b/doc/workbook/handling_cookies/example/application.e index 267333c4..cf939f60 100644 --- a/doc/workbook/handling_cookies/example/application.e +++ b/doc/workbook/handling_cookies/example/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that build a generic front to demonstrate the use of Cookies" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -21,133 +19,6 @@ feature {NONE} -- Initialization -- Initialize current service. do set_service_option ("port", 9090) - set_service_option ("verbose",True) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_message: STRING - l_header: HTTP_HEADER - l_time: HTTP_DATE - l_cookies: STRING - l_answer: STRING - do - -- all the cookies - create l_cookies.make_empty - across req.cookies as ic loop - l_cookies.append (ic.item.name) - l_cookies.append("
") - end - - if req.path_info.same_string ("/") then - create l_header.make - create l_answer.make_from_string (web_page) - if req.cookie ("_EWF_Cookie") = Void then - -- First access the the home page, find a cookie with specific name `_EWF_Cookie' - l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess") - l_answer.replace_substring_all ("$cookies", l_cookies) - create l_time.make_now_utc - l_time.date_time.day_add (40) - l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True) - else - -- No a new access - l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!") - l_answer.replace_substring_all ("$cookies", l_cookies) - end - l_header.put_content_type_text_html - l_header.put_content_length (l_answer.count) - res.put_header_text (l_header.string) - res.put_string (l_answer) - - elseif req.path_info.same_string ("/visitors") then - create l_header.make - create l_answer.make_from_string (visit_page) - if req.cookie ("_visits") = Void then - -- First access the the visit page, find a cookie with specific name `_visits' - l_answer.replace_substring_all ("$visit", "1") - l_answer.replace_substring_all ("$cookies", l_cookies) - create l_time.make_now_utc - l_time.date_time.day_add (40) - l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True) - - else - if attached {WSF_STRING} req.cookie ("_visits") as l_visit then - create l_time.make_now_utc - l_time.date_time.day_add (40) - l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out ) - l_answer.replace_substring_all ("$cookies", l_cookies) - l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True) - end - end - create l_time.make_now_utc - l_time.date_time.second_add (120) - l_header.put_content_type_text_html - -- This cookie expires in 120 seconds, its valid for 120 seconds - l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True) - -- This is a session cookie, valid only to the current browsing session. - l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True) - l_header.put_content_length (l_answer.count) - res.add_header_text (l_header.string) - res.put_string (l_answer) - end - - end - -feature -- Home Page - - web_page: STRING = "[ - - - - EWF Handling Cookies - - -
-

$header_title

-
- -
- Visitors -
- -
-

Cookies for the home page

- $cookies -
- - -]" - - -visit_page: STRING = "[ - - - - EWF Handling Visit Page - - -
-

The number of visits is $visit

-
- -
-

Cookies for the Visit page

- $cookies -
-
- -
- Back to Home -
- - - - -]" - end diff --git a/doc/workbook/handling_cookies/example/application_execution.e b/doc/workbook/handling_cookies/example/application_execution.e new file mode 100644 index 00000000..56562904 --- /dev/null +++ b/doc/workbook/handling_cookies/example/application_execution.e @@ -0,0 +1,141 @@ +note + description : "Basic Service that build a generic front to demonstrate the use of Cookies" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_message: STRING + l_header: HTTP_HEADER + l_time: HTTP_DATE + l_cookies: STRING + l_answer: STRING + do + -- all the cookies + create l_cookies.make_empty + across request.cookies as ic loop + l_cookies.append (ic.item.name) + l_cookies.append("
") + end + + if request.path_info.same_string ("/") then + create l_header.make + create l_answer.make_from_string (web_page) + if request.cookie ("_EWF_Cookie") = Void then + -- First access the the home page, find a cookie with specific name `_EWF_Cookie' + l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess") + l_answer.replace_substring_all ("$cookies", l_cookies) + create l_time.make_now_utc + l_time.date_time.day_add (40) + l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True) + else + -- No a new access + l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!") + l_answer.replace_substring_all ("$cookies", l_cookies) + end + l_header.put_content_type_text_html + l_header.put_content_length (l_answer.count) + response.put_header_text (l_header.string) + response.put_string (l_answer) + + elseif request.path_info.same_string ("/visitors") then + create l_header.make + create l_answer.make_from_string (visit_page) + if request.cookie ("_visits") = Void then + -- First access the the visit page, find a cookie with specific name `_visits' + l_answer.replace_substring_all ("$visit", "1") + l_answer.replace_substring_all ("$cookies", l_cookies) + create l_time.make_now_utc + l_time.date_time.day_add (40) + l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True) + + else + if attached {WSF_STRING} request.cookie ("_visits") as l_visit then + create l_time.make_now_utc + l_time.date_time.day_add (40) + l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out ) + l_answer.replace_substring_all ("$cookies", l_cookies) + l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True) + end + end + create l_time.make_now_utc + l_time.date_time.second_add (120) + l_header.put_content_type_text_html + -- This cookie expires in 120 seconds, its valid for 120 seconds + l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True) + -- This is a session cookie, valid only to the current browsing session. + l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True) + l_header.put_content_length (l_answer.count) + response.add_header_text (l_header.string) + response.put_string (l_answer) + end + + end + +feature -- Home Page + + web_page: STRING = "[ + + + + EWF Handling Cookies + + +
+

$header_title

+
+ +
+ Visitors +
+ +
+

Cookies for the home page

+ $cookies +
+ + +]" + + +visit_page: STRING = "[ + + + + EWF Handling Visit Page + + +
+

The number of visits is $visit

+
+ +
+

Cookies for the Visit page

+ $cookies +
+
+ +
+ Back to Home +
+ + + + +]" + +end diff --git a/doc/workbook/handling_request/form/get/application.e b/doc/workbook/handling_request/form/get/application.e index c857a0d8..cf939f60 100644 --- a/doc/workbook/handling_request/form/get/application.e +++ b/doc/workbook/handling_request/form/get/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that show how to handle a GET request" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,90 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - file: WSF_FILE_RESPONSE - l_parameter_names: STRING - l_answer: STRING - idioms: LIST[STRING] - l_raw_data: STRING - do - if req.is_get_request_method then - if req.path_info.same_string ("/") then - create file.make_html ("form.html") - res.send (file) - elseif req.path_info.same_string ("/search") then - - -- (1) the parameter is case sensitive - if not (attached req.query_parameter ("GIVEN-NAME")) then - -- Wrong `GIVEN-NAME' need to be in lower case. - end - - -- (2) Multiple values - if attached {WSF_MULTIPLE_STRING} req.query_parameter ("languages") as l_languages then - -- Get all the associated values - create {ARRAYED_LIST[STRING]} idioms.make (2) - across l_languages as ic loop idioms.force (ic.item.value) end - elseif attached {WSF_STRING} req.query_parameter ("languages") as l_language then - -- Single value - print (l_language.value) - else - -- Value Missing - end - - -- Read the all parameters names and his values. - create l_parameter_names.make_from_string ("

Parameters Names

") - l_parameter_names.append ("
") - create l_answer.make_from_string ("

Parameter Names and Values

") - l_answer.append ("
") - across req.query_parameters as ic loop - l_parameter_names.append (ic.item.key) - l_parameter_names.append ("
") - - l_answer.append (ic.item.key) - l_answer.append_character ('=') - if attached {WSF_STRING} req.query_parameter (ic.item.key) as l_value then - l_answer.append_string (l_value.value) - end - l_answer.append ("
") - end - - l_parameter_names.append ("
") - l_parameter_names.append_string (l_answer) - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) - res.put_string (l_parameter_names) - elseif req.path_info.same_string ("/link") then - -- WSF_TABLE example - create l_parameter_names.make_from_string ("

Parameters Name

") - if attached {WSF_TABLE} req.query_parameter ("tab") as l_tab then - l_parameter_names.append ("
") - l_parameter_names.append (l_tab.name) - - from - l_tab.values.start - until - l_tab.values.after - loop - l_parameter_names.append ("
") - l_parameter_names.append (l_tab.values.key_for_iteration) - if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then - l_parameter_names.append ("=") - l_parameter_names.append (l_value.value) - end - l_tab.values.forth - end - l_parameter_names.append ("
") - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) - res.put_string (l_parameter_names) - - end - else - -- Here we should handle unexpected errors. - end - end - end - end diff --git a/doc/workbook/handling_request/form/get/application_execution.e b/doc/workbook/handling_request/form/get/application_execution.e new file mode 100644 index 00000000..1fb05acd --- /dev/null +++ b/doc/workbook/handling_request/form/get/application_execution.e @@ -0,0 +1,101 @@ +note + description : "Basic Service that show how to handle a GET request" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + file: WSF_FILE_RESPONSE + l_parameter_names: STRING + l_answer: STRING + idioms: LIST[STRING] + l_raw_data: STRING + do + if request.is_get_request_method then + if request.path_info.same_string ("/") then + create file.make_html ("form.html") + response.send (file) + elseif request.path_info.same_string ("/search") then + + -- (1) the parameter is case sensitive + if not (attached request.query_parameter ("GIVEN-NAME")) then + -- Wrong `GIVEN-NAME' need to be in lower case. + end + + -- (2) Multiple values + if attached {WSF_MULTIPLE_STRING} request.query_parameter ("languages") as l_languages then + -- Get all the associated values + create {ARRAYED_LIST[STRING]} idioms.make (2) + across l_languages as ic loop idioms.force (ic.item.value) end + elseif attached {WSF_STRING} request.query_parameter ("languages") as l_language then + -- Single value + print (l_language.value) + else + -- Value Missing + end + + -- Read the all parameters names and his values. + create l_parameter_names.make_from_string ("

Parameters Names

") + l_parameter_names.append ("
") + create l_answer.make_from_string ("

Parameter Names and Values

") + l_answer.append ("
") + across request.query_parameters as ic loop + l_parameter_names.append (ic.item.key) + l_parameter_names.append ("
") + + l_answer.append (ic.item.key) + l_answer.append_character ('=') + if attached {WSF_STRING} request.query_parameter (ic.item.key) as l_value then + l_answer.append_string (l_value.value) + end + l_answer.append ("
") + end + + l_parameter_names.append ("
") + l_parameter_names.append_string (l_answer) + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) + response.put_string (l_parameter_names) + elseif request.path_info.same_string ("/link") then + -- WSF_TABLE example + create l_parameter_names.make_from_string ("

Parameters Name

") + if attached {WSF_TABLE} request.query_parameter ("tab") as l_tab then + l_parameter_names.append ("
") + l_parameter_names.append (l_tab.name) + + from + l_tab.values.start + until + l_tab.values.after + loop + l_parameter_names.append ("
") + l_parameter_names.append (l_tab.values.key_for_iteration) + if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then + l_parameter_names.append ("=") + l_parameter_names.append (l_value.value) + end + l_tab.values.forth + end + l_parameter_names.append ("
") + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) + response.put_string (l_parameter_names) + + end + else + -- Here we should handle unexpected errors. + end + end + end + +end diff --git a/doc/workbook/handling_request/form/post/application.e b/doc/workbook/handling_request/form/post/application.e index b388f390..cf939f60 100644 --- a/doc/workbook/handling_request/form/post/application.e +++ b/doc/workbook/handling_request/form/post/application.e @@ -1,13 +1,11 @@ note - description : "Reading Parameters from a HTML FORM (method POST) " - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,72 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - file: WSF_FILE_RESPONSE - l_parameter_names: STRING - l_answer: STRING - idioms: LIST[STRING] - l_raw_data: STRING - do - if req.is_get_request_method then - create file.make_html ("form.html") - res.send (file) - elseif req.is_post_request_method then - req.set_raw_input_data_recorded (True) - - -- (3) Read Raw Data - create l_raw_data.make_empty - req.read_input_data_into (l_raw_data) - - -- (1) the parameter is case sensitive - if not (attached req.form_parameter ("GIVEN-NAME")) then - -- Wrong `GIVEN-NAME' need to be in lower case. - end - - -- (2) Multiple values - if attached {WSF_MULTIPLE_STRING} req.form_parameter ("languages") as l_languages then - -- Get all the associated values - create {ARRAYED_LIST[STRING]} idioms.make (2) - across l_languages as ic loop idioms.force (ic.item.value) end - elseif attached {WSF_STRING} req.form_parameter ("langauges") as l_language then - -- Single value - print (l_language.value) - else - -- Value Missing - end - - -- Read the all parameters names and his values. - create l_parameter_names.make_from_string ("

Parameters Names

") - l_parameter_names.append ("
") - create l_answer.make_from_string ("

Parameter Names and Values

") - l_answer.append ("
") - - across req.form_parameters as ic loop - l_parameter_names.append (ic.item.key) - l_parameter_names.append ("
") - - l_answer.append (ic.item.key) - l_answer.append_character ('=') - if attached {WSF_STRING} req.form_parameter (ic.item.key) as l_value then - l_answer.append_string (l_value.value) - end - l_answer.append ("
") - end - - l_parameter_names.append ("
") - l_parameter_names.append_string (l_answer) - l_parameter_names.append ("
") - l_parameter_names.append ("

Raw content

") - l_parameter_names.append (l_raw_data) - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) - res.put_string (l_parameter_names) - else - -- Here we should handle unexpected errors. - end - end - end diff --git a/doc/workbook/handling_request/form/post/application_execution.e b/doc/workbook/handling_request/form/post/application_execution.e new file mode 100644 index 00000000..d893804e --- /dev/null +++ b/doc/workbook/handling_request/form/post/application_execution.e @@ -0,0 +1,83 @@ +note + description : "Reading Parameters from a HTML FORM (method POST) " + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + file: WSF_FILE_RESPONSE + l_parameter_names: STRING + l_answer: STRING + idioms: LIST[STRING] + l_raw_data: STRING + do + if request.is_get_request_method then + create file.make_html ("form.html") + response.send (file) + elseif request.is_post_request_method then + request.set_raw_input_data_recorded (True) + + -- (3) Read Raw Data + create l_raw_data.make_empty + request.read_input_data_into (l_raw_data) + + -- (1) the parameter is case sensitive + if not (attached request.form_parameter ("GIVEN-NAME")) then + -- Wrong `GIVEN-NAME' need to be in lower case. + end + + -- (2) Multiple values + if attached {WSF_MULTIPLE_STRING} request.form_parameter ("languages") as l_languages then + -- Get all the associated values + create {ARRAYED_LIST[STRING]} idioms.make (2) + across l_languages as ic loop idioms.force (ic.item.value) end + elseif attached {WSF_STRING} request.form_parameter ("langauges") as l_language then + -- Single value + print (l_language.value) + else + -- Value Missing + end + + -- Read the all parameters names and his values. + create l_parameter_names.make_from_string ("

Parameters Names

") + l_parameter_names.append ("
") + create l_answer.make_from_string ("

Parameter Names and Values

") + l_answer.append ("
") + + across request.form_parameters as ic loop + l_parameter_names.append (ic.item.key) + l_parameter_names.append ("
") + + l_answer.append (ic.item.key) + l_answer.append_character ('=') + if attached {WSF_STRING} request.form_parameter (ic.item.key) as l_value then + l_answer.append_string (l_value.value) + end + l_answer.append ("
") + end + + l_parameter_names.append ("
") + l_parameter_names.append_string (l_answer) + l_parameter_names.append ("
") + l_parameter_names.append ("

Raw content

") + l_parameter_names.append (l_raw_data) + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>) + response.put_string (l_parameter_names) + else + -- Here we should handle unexpected errors. + end + end + +end diff --git a/doc/workbook/handling_request/headers/browser_name/application.e b/doc/workbook/handling_request/headers/browser_name/application.e index d793f479..cf939f60 100644 --- a/doc/workbook/handling_request/headers/browser_name/application.e +++ b/doc/workbook/handling_request/headers/browser_name/application.e @@ -1,14 +1,11 @@ note - description : "Basic Service that Read a Request, a " - date : "$Date$" - revision : "$Revision$" - EIS: "name=Browser detection using user agent","src=https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent", "protocol=url" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -22,88 +19,6 @@ feature {NONE} -- Initialization -- Initialize current service. do set_service_option ("port", 9090) - set_service_option ("verbose", true) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_raw_data: STRING - l_page_response: STRING - l_rows: STRING - do - create l_page_response.make_from_string (html_template) - if req.path_info.same_string ("/") then - - -- retrieve the user-agent - if attached req.http_user_agent as l_user_agent then - l_page_response.replace_substring_all ("$user_agent", l_user_agent) - l_page_response.replace_substring_all ("$browser", get_browser_name (l_user_agent)) - else - l_page_response.replace_substring_all ("$user_agent", "[]") - l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.") - end - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) - res.put_string (l_page_response) - end - end - - -feature -- Browser utility - - get_browser_name (a_user_agent: READABLE_STRING_8):READABLE_STRING_32 - -- Must contain Must not contain - -- Firefox Firefox/xyz Seamonkey/xyz - -- Seamonkey Seamonkey/xyz - -- Chrome Chrome/xyz Chromium/xyz - -- Chromium Chromium/xyz - -- Safari Safari/xyz Chrome/xyz - -- Chromium/xyz - -- Opera OPR/xyz [1] - -- Opera/xyz [2] - -- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format - - do - if - a_user_agent.has_substring ("Firefox") and then - not a_user_agent.has_substring ("Seamonkey") - then - Result := "Firefox" - elseif a_user_agent.has_substring ("Seamonkey") then - Result := "Seamonkey" - elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then - Result := "Chrome" - elseif a_user_agent.has_substring ("Chromium") then - Result := "Chromiun" - elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then - Result := "Safari" - elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then - Result := "Opera" - elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then - Result := "Internet Explorer" - else - Result := "Unknown" - end - end - - - html_template: STRING = "[ - - - - - - -

EWF service example: Showing Browser Dectection Using User-Agent


- - User Agent: $user_agent
- -

Enjoy using $browser

- - - ]" - - end diff --git a/doc/workbook/handling_request/headers/browser_name/application_execution.e b/doc/workbook/handling_request/headers/browser_name/application_execution.e new file mode 100644 index 00000000..8ef85fd0 --- /dev/null +++ b/doc/workbook/handling_request/headers/browser_name/application_execution.e @@ -0,0 +1,97 @@ +note + description : "Basic Service that Read a Request, a " + date : "$Date$" + revision : "$Revision$" + EIS: "name=Browser detection using user agent","src=https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent", "protocol=url" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_raw_data: STRING + l_page_response: STRING + l_rows: STRING + do + create l_page_response.make_from_string (html_template) + if request.path_info.same_string ("/") then + + -- retrieve the user-agent + if attached request.http_user_agent as l_user_agent then + l_page_response.replace_substring_all ("$user_agent", l_user_agent) + l_page_response.replace_substring_all ("$browser", browser_name (l_user_agent)) + else + l_page_response.replace_substring_all ("$user_agent", "[]") + l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.") + end + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) + response.put_string (l_page_response) + end + end + + +feature -- Browser utility + + browser_name (a_user_agent: READABLE_STRING_8): STRING_8 + -- Must contain Must not contain + -- Firefox Firefox/xyz Seamonkey/xyz + -- Seamonkey Seamonkey/xyz + -- Chrome Chrome/xyz Chromium/xyz + -- Chromium Chromium/xyz + -- Safari Safari/xyz Chrome/xyz + -- Chromium/xyz + -- Opera OPR/xyz [1] + -- Opera/xyz [2] + -- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format + + do + if + a_user_agent.has_substring ("Firefox") and then + not a_user_agent.has_substring ("Seamonkey") + then + Result := "Firefox" + elseif a_user_agent.has_substring ("Seamonkey") then + Result := "Seamonkey" + elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then + Result := "Chrome" + elseif a_user_agent.has_substring ("Chromium") then + Result := "Chromiun" + elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then + Result := "Safari" + elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then + Result := "Opera" + elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then + Result := "Internet Explorer" + else + Result := "Unknown" + end + end + + + html_template: STRING = "[ + + + + + + +

EWF service example: Showing Browser Dectection Using User-Agent


+ + User Agent: $user_agent
+ +

Enjoy using $browser

+ + + ]" + + +end diff --git a/doc/workbook/handling_request/headers/cgi_variables/application.e b/doc/workbook/handling_request/headers/cgi_variables/application.e index 718d5770..cf939f60 100644 --- a/doc/workbook/handling_request/headers/cgi_variables/application.e +++ b/doc/workbook/handling_request/headers/cgi_variables/application.e @@ -1,14 +1,11 @@ note - description : "Basic Service that shows the standard CGI variables" - date : "$Date$" - revision : "$Revision$" - EIS: "name=CGI specification","src=(https://tools.ietf.org/html/rfc3875", "protocol=url" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -22,294 +19,6 @@ feature {NONE} -- Initialization -- Initialize current service. do set_service_option ("port", 9090) - set_service_option ("verbose", true) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_raw_data: STRING - l_page_response: STRING - l_rows: STRING - do - create l_page_response.make_from_string (html_template) - if req.path_info.same_string ("/") then - - -- HTTP method - l_page_response.replace_substring_all ("$http_method", req.request_method) - -- URI - l_page_response.replace_substring_all ("$uri", req.path_info) - -- Protocol - l_page_response.replace_substring_all ("$protocol", req.server_protocol) - - -- Fill the table rows with CGI standard variables - create l_rows.make_empty - - -- Auth_type - l_rows.append ("") - l_rows.append ("") - l_rows.append ("AUTH_TYPE") - l_rows.append ("") - l_rows.append ("") - if attached req.auth_type as l_type then - l_rows.append (l_type) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - -- Content length - l_rows.append ("") - l_rows.append ("") - l_rows.append ("CONTENT_LENGTH") - l_rows.append ("") - l_rows.append ("") - if attached req.content_length as l_content_length then - l_rows.append (l_content_length) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - -- Content length - l_rows.append ("") - l_rows.append ("") - l_rows.append ("CONTENT_TYPE") - l_rows.append ("") - l_rows.append ("") - if attached req.content_type as l_content_type then - l_rows.append (l_content_type.string) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - -- Gateway interface - l_rows.append ("") - l_rows.append ("") - l_rows.append ("GATEWAY_INTERFACE") - l_rows.append ("") - l_rows.append ("") - if attached req.gateway_interface as l_gateway_interface then - l_rows.append (l_gateway_interface) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - -- Path info - l_rows.append ("") - l_rows.append ("") - l_rows.append ("PATH_INFO") - l_rows.append ("") - l_rows.append ("") - if attached req.path_info as l_path_info then - l_rows.append (l_path_info) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - -- Path translated - l_rows.append ("") - l_rows.append ("") - l_rows.append ("PATH_TRANSLATED") - l_rows.append ("") - l_rows.append ("") - if attached req.path_translated as l_path_translated then - l_rows.append (l_path_translated) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - -- Query string - l_rows.append ("") - l_rows.append ("") - l_rows.append ("QUERY_STRING") - l_rows.append ("") - l_rows.append ("") - if attached req.query_string as l_query_string then - l_rows.append (l_query_string) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - -- Remote addr - l_rows.append ("") - l_rows.append ("") - l_rows.append ("REMOTE_ADDR") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.remote_addr) - l_rows.append ("") - l_rows.append ("") - - - -- Remote host - l_rows.append ("") - l_rows.append ("") - l_rows.append ("REMOTE_HOST") - l_rows.append ("") - l_rows.append ("") - if attached req.remote_host as l_remote_host then - l_rows.append (l_remote_host) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - - -- Remote ident - l_rows.append ("") - l_rows.append ("") - l_rows.append ("REMOTE_IDENT") - l_rows.append ("") - l_rows.append ("") - if attached req.remote_ident as l_remote_ident then - l_rows.append (l_remote_ident) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - -- Remote user - l_rows.append ("") - l_rows.append ("") - l_rows.append ("REMOTE_USER") - l_rows.append ("") - l_rows.append ("") - if attached req.remote_user as l_remote_user then - l_rows.append (l_remote_user) - else - l_rows.append ("Not present") - end - l_rows.append ("") - l_rows.append ("") - - - -- Request method - l_rows.append ("") - l_rows.append ("") - l_rows.append ("REQUEST_METHOD") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.request_method) - l_rows.append ("") - l_rows.append ("") - - - -- Script name - l_rows.append ("") - l_rows.append ("") - l_rows.append ("SCRIPT_NAME") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.script_name) - l_rows.append ("") - l_rows.append ("") - - -- Server name - l_rows.append ("") - l_rows.append ("") - l_rows.append ("SERVER_NAME") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.server_name) - l_rows.append ("") - l_rows.append ("") - - -- Server protocol - l_rows.append ("") - l_rows.append ("") - l_rows.append ("SERVER_PROTOCOL") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.server_protocol) - l_rows.append ("") - l_rows.append ("") - - -- Server software - l_rows.append ("") - l_rows.append ("") - l_rows.append ("SERVER_SOFTWARE") - l_rows.append ("") - l_rows.append ("") - l_rows.append (req.server_software) - l_rows.append ("") - l_rows.append ("") - - - l_page_response.replace_substring_all ("$rows", l_rows) - - -- Reading the raw header - if attached req.raw_header_data as l_raw_header then - l_page_response.replace_substring_all ("$raw_header", l_raw_header) - end - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) - res.put_string (l_page_response) - end - end - - - - html_template: STRING = "[ - - - - - - - -

EWF service example: Showing Standard CGI Variables

- - HTTP METHOD:$http_method
- URI:$uri
- PROTOCOL:$protocol
- -
- - - - - - - - - $rows - -
CGI NameValue
- - -

Raw header

- - $raw_header - - - ]" - - end diff --git a/doc/workbook/handling_request/headers/cgi_variables/application_execution.e b/doc/workbook/handling_request/headers/cgi_variables/application_execution.e new file mode 100644 index 00000000..10063855 --- /dev/null +++ b/doc/workbook/handling_request/headers/cgi_variables/application_execution.e @@ -0,0 +1,303 @@ +note + description : "Basic Service that shows the standard CGI variables" + date : "$Date$" + revision : "$Revision$" + EIS: "name=CGI specification","src=(https://tools.ietf.org/html/rfc3875", "protocol=url" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_raw_data: STRING + l_page_response: STRING + l_rows: STRING + do + create l_page_response.make_from_string (html_template) + if request.path_info.same_string ("/") then + + -- HTTP method + l_page_response.replace_substring_all ("$http_method", request.request_method) + -- URI + l_page_response.replace_substring_all ("$uri", request.path_info) + -- Protocol + l_page_response.replace_substring_all ("$protocol", request.server_protocol) + + -- Fill the table rows with CGI standard variables + create l_rows.make_empty + + -- Auth_type + l_rows.append ("") + l_rows.append ("") + l_rows.append ("AUTH_TYPE") + l_rows.append ("") + l_rows.append ("") + if attached request.auth_type as l_type then + l_rows.append (l_type) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + -- Content length + l_rows.append ("") + l_rows.append ("") + l_rows.append ("CONTENT_LENGTH") + l_rows.append ("") + l_rows.append ("") + if attached request.content_length as l_content_length then + l_rows.append (l_content_length) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + -- Content length + l_rows.append ("") + l_rows.append ("") + l_rows.append ("CONTENT_TYPE") + l_rows.append ("") + l_rows.append ("") + if attached request.content_type as l_content_type then + l_rows.append (l_content_type.string) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + -- Gateway interface + l_rows.append ("") + l_rows.append ("") + l_rows.append ("GATEWAY_INTERFACE") + l_rows.append ("") + l_rows.append ("") + if attached request.gateway_interface as l_gateway_interface then + l_rows.append (l_gateway_interface) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + -- Path info + l_rows.append ("") + l_rows.append ("") + l_rows.append ("PATH_INFO") + l_rows.append ("") + l_rows.append ("") + if attached request.path_info as l_path_info then + l_rows.append (l_path_info) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + -- Path translated + l_rows.append ("") + l_rows.append ("") + l_rows.append ("PATH_TRANSLATED") + l_rows.append ("") + l_rows.append ("") + if attached request.path_translated as l_path_translated then + l_rows.append (l_path_translated) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + -- Query string + l_rows.append ("") + l_rows.append ("") + l_rows.append ("QUERY_STRING") + l_rows.append ("") + l_rows.append ("") + if attached request.query_string as l_query_string then + l_rows.append (l_query_string) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + -- Remote addr + l_rows.append ("") + l_rows.append ("") + l_rows.append ("REMOTE_ADDR") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.remote_addr) + l_rows.append ("") + l_rows.append ("") + + + -- Remote host + l_rows.append ("") + l_rows.append ("") + l_rows.append ("REMOTE_HOST") + l_rows.append ("") + l_rows.append ("") + if attached request.remote_host as l_remote_host then + l_rows.append (l_remote_host) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + + -- Remote ident + l_rows.append ("") + l_rows.append ("") + l_rows.append ("REMOTE_IDENT") + l_rows.append ("") + l_rows.append ("") + if attached request.remote_ident as l_remote_ident then + l_rows.append (l_remote_ident) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + -- Remote user + l_rows.append ("") + l_rows.append ("") + l_rows.append ("REMOTE_USER") + l_rows.append ("") + l_rows.append ("") + if attached request.remote_user as l_remote_user then + l_rows.append (l_remote_user) + else + l_rows.append ("Not present") + end + l_rows.append ("") + l_rows.append ("") + + + -- Request method + l_rows.append ("") + l_rows.append ("") + l_rows.append ("REQUEST_METHOD") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.request_method) + l_rows.append ("") + l_rows.append ("") + + + -- Script name + l_rows.append ("") + l_rows.append ("") + l_rows.append ("SCRIPT_NAME") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.script_name) + l_rows.append ("") + l_rows.append ("") + + -- Server name + l_rows.append ("") + l_rows.append ("") + l_rows.append ("SERVER_NAME") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.server_name) + l_rows.append ("") + l_rows.append ("") + + -- Server protocol + l_rows.append ("") + l_rows.append ("") + l_rows.append ("SERVER_PROTOCOL") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.server_protocol) + l_rows.append ("") + l_rows.append ("") + + -- Server software + l_rows.append ("") + l_rows.append ("") + l_rows.append ("SERVER_SOFTWARE") + l_rows.append ("") + l_rows.append ("") + l_rows.append (request.server_software) + l_rows.append ("") + l_rows.append ("") + + + l_page_response.replace_substring_all ("$rows", l_rows) + + -- Reading the raw header + if attached request.raw_header_data as l_raw_header then + l_page_response.replace_substring_all ("$raw_header", l_raw_header) + end + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) + response.put_string (l_page_response) + end + end + + + + html_template: STRING = "[ + + + + + + + +

EWF service example: Showing Standard CGI Variables

+ + HTTP METHOD:$http_method
+ URI:$uri
+ PROTOCOL:$protocol
+ +
+ + + + + + + + + $rows + +
CGI NameValue
+ + +

Raw header

+ + $raw_header + + + ]" + + +end diff --git a/doc/workbook/handling_request/headers/header_fields/application.e b/doc/workbook/handling_request/headers/header_fields/application.e index 4d0729b0..cf939f60 100644 --- a/doc/workbook/handling_request/headers/header_fields/application.e +++ b/doc/workbook/handling_request/headers/header_fields/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that Read Request Headers" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -21,97 +19,6 @@ feature {NONE} -- Initialization -- Initialize current service. do set_service_option ("port", 9090) - set_service_option ("verbose", true) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - l_raw_data: STRING - l_page_response: STRING - l_rows: STRING - do - create l_page_response.make_from_string (html_template) - if req.path_info.same_string ("/") then - - -- HTTP method - l_page_response.replace_substring_all ("$http_method", req.request_method) - -- URI - l_page_response.replace_substring_all ("$uri", req.path_info) - -- Protocol - l_page_response.replace_substring_all ("$protocol", req.server_protocol) - - -- Fill the table rows with HTTP Headers - create l_rows.make_empty - across req.meta_variables as ic loop - if ic.item.name.starts_with ("HTTP_") then - l_rows.append ("") - l_rows.append ("") - l_rows.append (ic.item.name) - l_rows.append ("") - l_rows.append ("") - l_rows.append (ic.item.value) - l_rows.append ("") - l_rows.append ("") - end - end - - l_page_response.replace_substring_all ("$rows", l_rows) - - -- Reading the raw header - if attached req.raw_header_data as l_raw_header then - l_page_response.replace_substring_all ("$raw_header", l_raw_header) - end - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) - res.put_string (l_page_response) - end - end - - - - html_template: STRING = "[ - - - - - - - -

EWF service example: Showing Request Headers

- - HTTP METHOD:$http_method
- URI:$uri
- PROTOCOL:$protocol
- REQUEST TIME:$time
- -
- - - - - - - - - $rows - -
Header NameHeader Value
- - -

Raw header

- - $raw_header - - - ]" - - end diff --git a/doc/workbook/handling_request/headers/header_fields/application_execution.e b/doc/workbook/handling_request/headers/header_fields/application_execution.e new file mode 100644 index 00000000..9f3242fc --- /dev/null +++ b/doc/workbook/handling_request/headers/header_fields/application_execution.e @@ -0,0 +1,105 @@ +note + description : "Basic Service that Read Request Headers" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + l_raw_data: STRING + l_page_response: STRING + l_rows: STRING + do + create l_page_response.make_from_string (html_template) + if request.path_info.same_string ("/") then + + -- HTTP method + l_page_response.replace_substring_all ("$http_method", request.request_method) + -- URI + l_page_response.replace_substring_all ("$uri", request.path_info) + -- Protocol + l_page_response.replace_substring_all ("$protocol", request.server_protocol) + + -- Fill the table rows with HTTP Headers + create l_rows.make_empty + across request.meta_variables as ic loop + if ic.item.name.starts_with ("HTTP_") then + l_rows.append ("") + l_rows.append ("") + l_rows.append (ic.item.name) + l_rows.append ("") + l_rows.append ("") + l_rows.append (ic.item.value) + l_rows.append ("") + l_rows.append ("") + end + end + + l_page_response.replace_substring_all ("$rows", l_rows) + + -- Reading the raw header + if attached request.raw_header_data as l_raw_header then + l_page_response.replace_substring_all ("$raw_header", l_raw_header) + end + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>) + response.put_string (l_page_response) + end + end + + + + html_template: STRING = "[ + + + + + + + +

EWF service example: Showing Request Headers

+ + HTTP METHOD:$http_method
+ URI:$uri
+ PROTOCOL:$protocol
+ REQUEST TIME:$time
+ +
+ + + + + + + + + $rows + +
Header NameHeader Value
+ + +

Raw header

+ + $raw_header + + + ]" + + +end diff --git a/doc/workbook/handling_request/upload_file/application.e b/doc/workbook/handling_request/upload_file/application.e index b37c0790..cf939f60 100644 --- a/doc/workbook/handling_request/upload_file/application.e +++ b/doc/workbook/handling_request/upload_file/application.e @@ -1,13 +1,11 @@ note - description : "Basic Service that show how to Upload a file" - date : "$Date$" - revision : "$Revision$" + description: "Basic Service launcher" class APPLICATION inherit - WSF_DEFAULT_SERVICE + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] redefine initialize end @@ -23,47 +21,4 @@ feature {NONE} -- Initialization set_service_option ("port", 9090) end -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incomming request - local - file: WSF_FILE_RESPONSE - l_answer: STRING - do - if req.is_get_request_method then - if req.path_info.same_string ("/") then - create file.make_html ("upload.html") - res.send (file) - else - -- Here we should handle unexpected errors. - end - elseif req.is_post_request_method then - if req.path_info.same_string ("/upload") then - -- Check if we have an uploaded file - if req.has_uploaded_file then - -- iterate over all the uploaded files - create l_answer.make_from_string ("

Uploaded File/s


") - across req.uploaded_files as ic loop - l_answer.append ("FileName:") - l_answer.append (ic.item.filename) - l_answer.append ("
Size:") - l_answer.append (ic.item.size.out) - l_answer.append ("
") - end - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>) - res.put_string (l_answer) - else - -- Here we should handle unexpected errors. - create l_answer.make_from_string ("No uploaded files
") - create l_answer.append ("Back to Home") - res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>) - res.put_string (l_answer) - end - else - -- Handle error - end - end - end - end diff --git a/doc/workbook/handling_request/upload_file/application_execution.e b/doc/workbook/handling_request/upload_file/application_execution.e new file mode 100644 index 00000000..8186494e --- /dev/null +++ b/doc/workbook/handling_request/upload_file/application_execution.e @@ -0,0 +1,58 @@ +note + description : "Basic Service that show how to Upload a file" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_EXECUTION + +inherit + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute + -- Execute the incomming request + local + file: WSF_FILE_RESPONSE + l_answer: STRING + do + if request.is_get_request_method then + if request.path_info.same_string ("/") then + create file.make_html ("upload.html") + response.send (file) + else + -- Here we should handle unexpected errors. + end + elseif request.is_post_request_method then + if request.path_info.same_string ("/upload") then + -- Check if we have an uploaded file + if request.has_uploaded_file then + -- iterate over all the uploaded files + create l_answer.make_from_string ("

Uploaded File/s


") + across request.uploaded_files as ic loop + l_answer.append ("FileName:") + l_answer.append (ic.item.filename) + l_answer.append ("
Size:") + l_answer.append (ic.item.size.out) + l_answer.append ("
") + end + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>) + response.put_string (l_answer) + else + -- Here we should handle unexpected errors. + create l_answer.make_from_string ("No uploaded files
") + l_answer.append ("Back to Home") + response.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>) + response.put_string (l_answer) + end + else + -- Handle error + end + end + end + +end From 903f925a793ca6b3a02cb448606ae34b0863cf71 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 17 Jun 2015 17:22:59 +0200 Subject: [PATCH 12/36] Changed the way SSL is supported with standalone connector (httpd lib). Now by default, SSL is not supported, and if an application wants the SSL support, the related .ecf has to set custom variable "httpd_ssl_enabled" to "true" --- .../standalone/src/httpd/httpd-safe.ecf | 6 +-- .../connectors/standalone/src/httpd/httpd.ecf | 6 +-- library/server/wsf/package.iron | 39 +++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 library/server/wsf/package.iron diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf index 2641135a..0a672db8 100644 --- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf +++ b/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf @@ -15,7 +15,7 @@ - + @@ -33,12 +33,12 @@ - + - + diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf b/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf index aa6a08a0..4dae6c58 100644 --- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf +++ b/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf @@ -15,7 +15,7 @@ - + @@ -34,12 +34,12 @@ - + - + diff --git a/library/server/wsf/package.iron b/library/server/wsf/package.iron new file mode 100644 index 00000000..56045dd0 --- /dev/null +++ b/library/server/wsf/package.iron @@ -0,0 +1,39 @@ +package wsf + +project + wsf = "wsf-safe.ecf" + wsf = "wsf.ecf" + wsf_extension = "wsf_extension-safe.ecf" + wsf_extension = "wsf_extension.ecf" + wsf_policy_driven = "wsf_policy_driven-safe.ecf" + wsf_policy_driven = "wsf_policy_driven.ecf" + wsf_router_context = "wsf_router_context-safe.ecf" + wsf_router_context = "wsf_router_context.ecf" + wsf_session = "wsf_session-safe.ecf" + wsf_session = "wsf_session.ecf" + wsf_all = "connector/all-safe.ecf" + wsf_cgi = "connector/cgi-safe.ecf" + wsf_cgi = "connector/cgi.ecf" + wsf_libfcgi = "connector/libfcgi-safe.ecf" + wsf_libfcgi = "connector/libfcgi.ecf" + wsf_nino = "connector/nino-safe.ecf" + wsf_nino = "connector/nino.ecf" + wsf_openshift = "connector/openshift-safe.ecf" + default_cgi = "default/cgi-safe.ecf" + default_cgi = "default/cgi.ecf" + default_libfcgi = "default/libfcgi-safe.ecf" + default_libfcgi = "default/libfcgi.ecf" + default_nino = "default/nino-safe.ecf" + default_nino = "default/nino.ecf" + default_openshift = "default/openshift-safe.ecf" + +note + title: Web Server Foundation + description: Core of the Eiffel Web Framework, used to build web server application. + tags: ewf,server,httpd,request,connector + license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt) + link[license]: https://github.com/EiffelWebFramework/EWF/blob/master/LICENSE + link[source]: "Github" https://github.com/EiffelWebFramework/EWF + link[doc]: "Documentation" http://eiffelwebframework.github.io/EWF/ + +end From 54dd43c38aa6df52a11d0de4f5457f4279588768 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 18 Jun 2015 14:53:19 +0200 Subject: [PATCH 13/36] Synchronized wsf-safe.ecf and wsf.ecf --- library/server/wsf/wsf.ecf | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/server/wsf/wsf.ecf b/library/server/wsf/wsf.ecf index 5f0269d8..df505eb9 100644 --- a/library/server/wsf/wsf.ecf +++ b/library/server/wsf/wsf.ecf @@ -1,5 +1,5 @@ - + @@ -9,23 +9,23 @@ - + + + - - - - - - - - - + + + + + + + + /policy_driven$ + From 99a05b95baa6e4fd4d9009f3adc8951e43cb2fb9 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 22 Jun 2015 22:06:16 +0200 Subject: [PATCH 14/36] Improved code related to cookie management (avoid duplicated cookie). --- library/server/wsf/src/wsf_response.e | 46 +++++++++++++++------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e index 32922fa1..f787dc8f 100644 --- a/library/server/wsf/src/wsf_response.e +++ b/library/server/wsf/src/wsf_response.e @@ -319,8 +319,8 @@ feature -- Header output operation: helpers feature -- Header add cookie add_cookie (a_cookie: WSF_COOKIE) - -- Add a Set-Cookie header field to the response, iff there is not exist - -- a Set-Cookie header field with the same cookie-name. + -- Add a Set-Cookie header field to the response, + -- if no Set-Cookie header field already use same cookie-name. --| Servers SHOULD NOT include more than one Set-Cookie header field in --| the same response with the same cookie-name. local @@ -328,7 +328,8 @@ feature -- Header add cookie do across internal_header.headers as ic - until l_same_cookie_name + until + l_same_cookie_name loop if ic.item.starts_with ("Set-Cookie:") then l_same_cookie_name := has_cookie_name (ic.item, a_cookie.name) @@ -544,24 +545,29 @@ feature -- Error reporting feature {NONE} -- Implemenation - has_cookie_name (a_cookie_line, a_cookie_name: READABLE_STRING_32 ): BOOLEAN - -- Has the cookie line `a_cookie_line', the cookie name `a_cookie_name'? - local - i,j: INTEGER - do - Result := False - i := a_cookie_line.index_of ('=', 1) + has_cookie_name (a_cookie_line, a_cookie_name: READABLE_STRING_GENERAL): BOOLEAN + -- Has the cookie line `a_cookie_line', the cookie name `a_cookie_name'? + local + i,j,n: INTEGER + do j := a_cookie_line.index_of (':', 1) - - if i > j and j > 0 then - i := i - 1 - j := j + 1 - from until not a_cookie_line[j].is_space loop - j := j + 1 - end - if a_cookie_name.same_characters (a_cookie_line, j, i, 1) then - Result := True - end + if j > 0 then + i := a_cookie_line.index_of ('=', 1) + if i > j then + i := i - 1 + j := j + 1 + -- Skip spaces. + from + n := a_cookie_line.count + until + j > n or not a_cookie_line[j].is_space + loop + j := j + 1 + end + if j > n then + Result := a_cookie_name.same_characters (a_cookie_line, j, i, 1) + end + end end end From f254b599c080178eb809c218d898f6ed46323d25 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Mon, 29 Jun 2015 16:17:43 -0300 Subject: [PATCH 15/36] Update basic document to the new EWF concurrent design --- doc/workbook/basics/APPLICATION_EXECUTION.png | Bin 0 -> 5971 bytes doc/workbook/basics/Launcher Hierarchy.png | Bin 0 -> 16595 bytes doc/workbook/basics/basics.md | 84 ++++++++++-------- 3 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 doc/workbook/basics/APPLICATION_EXECUTION.png create mode 100644 doc/workbook/basics/Launcher Hierarchy.png diff --git a/doc/workbook/basics/APPLICATION_EXECUTION.png b/doc/workbook/basics/APPLICATION_EXECUTION.png new file mode 100644 index 0000000000000000000000000000000000000000..270c78aa571825451c5620c5d424292dd348f7ac GIT binary patch literal 5971 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 literal 0 HcmV?d00001 diff --git a/doc/workbook/basics/Launcher Hierarchy.png b/doc/workbook/basics/Launcher Hierarchy.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c047237a1a71b690c29fd31dea6d7f93f77991 GIT binary patch literal 16595 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 ONa2;LY=!ijkpBh`q`oQu literal 0 HcmV?d00001 diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index e425620a..c26867f2 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -14,83 +14,89 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/wor ## EWF service structure -The following code describes the basic structure of an EWF basic service that handles HTTP requests. +The following code describes the basic structure of an EWF basic service that handles HTTP requests. We will need to define a Service Launcher and a Request Execution implementation. ```eiffel class - SERVICE_TEMPLATE + APPLICACTION inherit - WSF_DEFAULT_SERVICE -- Todo explain this, and the concept of launchers and connectors () + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] create - make_and_launch + make_and_launch -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - do - -- To read incoming HTTP request, we need to use `req' - - -- May require talking to databases or other services. - - -- To send a response we need to setup, the status code and - -- the response headers and the content we want to send out our client - end end ``` -When using the "nino" connector, by default the service listens on port 80, but often this port is already used by other applications, so it is recommended to use another port. -To define another port, redefine the feature `initialize' and set up a new port number using the service options (see below). +The class ```APPLICATION``` inherit from +```WSF_DEFAULT_SERVICE [G ->WSF_EXECUTION create make end]``` it will be responsible to launch the service an set optional options. + +The class ```APPLICATION_EXECUTION``` is an implementation ```WSF_EXECUTION``` interface, which is instantiated for each incoming request. ```eiffel class - SERVICE_TEMPLATE + APPLICATION_EXECUTION + inherit - WSF_DEFAULT_SERVICE - redefine + WSF_EXECUTION + +create + make + +feature -- Basic operations + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + do + -- To read incoming HTTP request, we need to use `req' + + -- May require talking to databases or other services. + + -- To send a response we need to setup, the status code and + -- the response headers and the content we want to send out our client + end +end +``` + +When using the "nino" connector or the new "standalone" connector, by default the service listens on port 80, but often this port is already used by other applications, so it is recommended to use another port. +To define another port, redefine the feature `initialize' and set up a new port number using the service options (see below). + + +```eiffel +class + APPLICATION + +inherit + WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION] + redefine initialize end create - make_and_launch + make_and_launch feature {NONE} -- Initialization initialize -- Initialize current service. - -- on port 9090 do set_service_option ("port", 9090) end - -feature -- Basic operations - - execute (req: WSF_REQUEST; res: WSF_RESPONSE) - -- Execute the incoming request. - do - -- To read incoming HTTP requires, we need to use `req' - - -- May require talking to databases or other services. - - -- To send a response we need to setup, the status code and - -- the response headers and the content we want to send out client - end end ``` The **WSF_REQUEST** gives access to the incoming data; the class provides features to get information such as request method, form data, query parameters, uploaded files, HTTP request headers, and hostname of the client among others. The **WSF_RESPONSE** provides features to define the response with information such as HTTP status codes (10x,20x, 30x, 40x, and 50x), response headers (Content-Type, Content-Length, etc.) and obviously the body of the message itself. -**SERVICE_TEMPLATE** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi or nino. For development is recommended to use Nino, a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server. +**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi, or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server. -The **SERVICE_TEMPLATE** class inherits from _WSF_DEFAULT_SERVICE_ class, and this one also inherits from other interfaces. Let’s describe them in a few words. +The **APPLICATION_EXECUTION** class inherits from _WSF_EXECUTION_ interface, which is instantiated for each incoming request. Let’s describe them in a few words. -![Service Template Hierarchy](/workbook/SERVICE_TEMPLATE.png "Service Template") +![Execution Hierarchy](/workbook/APPLICATION_EXECUTION.png "Application ExecUtion ") **WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```. And also provides a way to launch our application using different kind of connectors. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing the different kind of connectors. -![Launcher Hierarchy](/app/doc/WSF_SERVICE_LAUNCHER.png "Launcher") +![Launcher Hierarchy](./basic/Launcher Hierarchy.png "Launcher Hierarchy") A basic EWF service inherits from **WSF_DEFAULT_SERVICE** (for other options see [?]). And then you only need to implement the **execute** feature, get data from the request *req* and write the response in *res*. From 6e3a7deb6eebf3858e804b9b0a444762ce30c35e Mon Sep 17 00:00:00 2001 From: Javier Velilla Date: Mon, 29 Jun 2015 16:20:19 -0300 Subject: [PATCH 16/36] Update workbook.md --- doc/workbook/workbook.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/workbook/workbook.md b/doc/workbook/workbook.md index 37b7789b..aa68c191 100644 --- a/doc/workbook/workbook.md +++ b/doc/workbook/workbook.md @@ -19,20 +19,20 @@ Before reading (or walking throught) the workbook, to get a quick overview of EW ## Introduction -[Basic Concepts] (/workbook/basics/basics.md). +[Basic Concepts] (/doc/workbook/basics/basics.md). ## Handling Requests: Form/Query Parameter -[Handling Requests: Form/Query Parameter] (/workbook/handling_request/form.md). +[Handling Requests: Form/Query Parameter] (/doc/workbook/handling_request/form.md). ## Handling Requests: Header Fields -[Handling Requests: Header Fields](/workbook/handling_request/headers.md). +[Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md). ## Generating Response -[Generating Responses](/workbook/generating_response/generating_response.md) +[Generating Responses](/doc/workbook/generating_response/generating_response.md) ## Handling Cookies -[Handling Cookies](/workbook/handling_cookies/handling_cookies.md) +[Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md) From f2405e0ccd9b46f2e2079b4fb9bb1f3b7911c070 Mon Sep 17 00:00:00 2001 From: Javier Velilla Date: Mon, 29 Jun 2015 16:22:01 -0300 Subject: [PATCH 17/36] Update basics.md --- doc/workbook/basics/basics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index c26867f2..1dce4d0c 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -92,11 +92,11 @@ The **WSF_RESPONSE** provides features to define the response with information s The **APPLICATION_EXECUTION** class inherits from _WSF_EXECUTION_ interface, which is instantiated for each incoming request. Let’s describe them in a few words. -![Execution Hierarchy](/workbook/APPLICATION_EXECUTION.png "Application ExecUtion ") +![Execution Hierarchy](/doc/workbook/basic/APPLICATION_EXECUTION.png "Application ExecUtion ") **WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```. And also provides a way to launch our application using different kind of connectors. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing the different kind of connectors. -![Launcher Hierarchy](./basic/Launcher Hierarchy.png "Launcher Hierarchy") +![Launcher Hierarchy](/doc/workbook/basic/Launcher Hierarchy.png "Launcher Hierarchy") A basic EWF service inherits from **WSF_DEFAULT_SERVICE** (for other options see [?]). And then you only need to implement the **execute** feature, get data from the request *req* and write the response in *res*. From 9e06fb2ab8bf75d86f9d275c2e93c48c22408034 Mon Sep 17 00:00:00 2001 From: Javier Velilla Date: Mon, 29 Jun 2015 16:24:09 -0300 Subject: [PATCH 18/36] Update basics.md --- doc/workbook/basics/basics.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index 1dce4d0c..523381a1 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -1,4 +1,4 @@ -Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md) ## EWF basic service @@ -92,11 +92,11 @@ The **WSF_RESPONSE** provides features to define the response with information s The **APPLICATION_EXECUTION** class inherits from _WSF_EXECUTION_ interface, which is instantiated for each incoming request. Let’s describe them in a few words. -![Execution Hierarchy](/doc/workbook/basic/APPLICATION_EXECUTION.png "Application ExecUtion ") +![Execution Hierarchy](/doc/workbook/basics/APPLICATION_EXECUTION.png "Application ExecUtion ") **WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```. And also provides a way to launch our application using different kind of connectors. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing the different kind of connectors. -![Launcher Hierarchy](/doc/workbook/basic/Launcher Hierarchy.png "Launcher Hierarchy") +![Launcher Hierarchy](/doc/workbook/basics/Launcher Hierarchy.png "Launcher Hierarchy") A basic EWF service inherits from **WSF_DEFAULT_SERVICE** (for other options see [?]). And then you only need to implement the **execute** feature, get data from the request *req* and write the response in *res*. @@ -213,5 +213,5 @@ The example of the service that generates HTML is located in the directory $PATH ```estudio -config simple_html.ecf -target simple_html_nino``` -Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md) From 57048373f4cbef2a7dbee497abc1f664889dd0b7 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Mon, 29 Jun 2015 18:30:11 -0300 Subject: [PATCH 19/36] Update basic document --- .../basics/WSF_SERVICE_LAUNCHER_CGI.png | Bin 0 -> 9471 bytes .../basics/WSF_SERVICE_LAUNCHER_FCGI.png | Bin 0 -> 9552 bytes .../basics/WSF_SERVICE_LAUNCHER_NINO.png | Bin 0 -> 9523 bytes .../WSF_SERVICE_LAUNCHER_STANDALONE.png | Bin 0 -> 11031 bytes doc/workbook/basics/basics.md | 32 +++++++++++++----- doc/workbook/basics/simple/simple.ecf | 8 +++++ 6 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 doc/workbook/basics/WSF_SERVICE_LAUNCHER_CGI.png create mode 100644 doc/workbook/basics/WSF_SERVICE_LAUNCHER_FCGI.png create mode 100644 doc/workbook/basics/WSF_SERVICE_LAUNCHER_NINO.png create mode 100644 doc/workbook/basics/WSF_SERVICE_LAUNCHER_STANDALONE.png diff --git a/doc/workbook/basics/WSF_SERVICE_LAUNCHER_CGI.png b/doc/workbook/basics/WSF_SERVICE_LAUNCHER_CGI.png new file mode 100644 index 0000000000000000000000000000000000000000..ba484064766681fff3b3cfb3fda0a16a9d58fa76 GIT binary patch literal 9471 zcmd7Ybx>Tvx*+hu2~L0@!6$*if|CSDa2R|b!7UJUumlTkK?VyMB)Gc=$l#U)cNv`E z?mjqga^Ke8ty^#FRqei4yMLTIRb5kE-Cuv_oc?~(VGuP1Vgfn>002O&2$t0Z05F8n z7X>~pxvylOT*qmph09snMiyVO{pSs>D)j~U=SE5PaYpmpcF;MO7(yB!y_hR zD}VQ)t+9gUL1`KH(@prK9y8rj*luw`&}L#a2HW?rF83S|KscxCM%|ncZ_8O6J7xW0eXktP1%;RW|C^`>vG|*ikRSoai@)O-{bYG221In4QT^=Ud{G1x?v4DqjA}N@ ze!j&j9NsVS0UYWFf9V-34~7Wo*YBQ) zI+S6;6zo|VDTlYO|#H zrR4Gm=H^U~=q)Zvy%UV~IhFQCe5$G86MER$Ip6C4Yr@CdotQqtyLjK(DE6nOez$4K>+fw7^LKh} zh(A<&G@tq$qJ6}hD&`BkNYhQ{WP9D*J+4{Y*f>|mwDtBN_s!ei#mjyBLq4az_L-S9 zJGt$PRL^*A#QLMY9+5BfT&xB1Vb{Z0$3BCl`B8||8g|HpZ-<)cb?f2XrBv!ww#@7X z^Rv`3zalZdyIWd%u9x}RbSb{~^@1G&TO0|!a}E$KSEQkSwsyF3+|sczpMY337RGqrEI6Sov1D81G4pAH zRx+VQ)31BQ=o0|LJAA0Y`GUEnZp)-{r0iWL1>kju)gP}q)M64#8EC)mVVaPr&#PvL zynj^LsPmqk{nAw4(Xq2$Pq|>YSYwFgJFIEHn9e>p#pXfe@@}^_4!>5uvl(uI2vf51 z2)o4@=6itrihNX}`AOGZh**&+@7=&HOY(RZ+y#Z_9wMboZaR<(*c=cAnPyYwVqFp{DN91=ZX z$t176il0+zZ4zK;{Nb&UD4tqit?3nYUxTalODK2p4d{?f<^wWQzLM zCff|e&UY#v-Sp9mw%A`phi-gQQ~k=+aMtK&{tHG)onc)?Q9iPly4HdF=mpWu9TMHP zF=JAHxs8P>e*eJaEQ)3Hc?fuc*eN%t6g&iE=6R}*jFx$P5 z))1SM$UR)qr?D!_#wx)hbPthTpm}I9Yb5U_2`Rkse1O0733nLB$ggnGhmp4|IW|or zwS)Lc`eu!X-UI=vm+OX2WC1+zNg4~_l6lh2=v$wGtHer)Fxk7+ZgFY+8&HEf(WJl@ zFHgTqw*4idySK^|V0GY_j#-^ZRj8LAkE#LH`Xk?)k_imQBuU;om#xgKs=bw^Rbo4r zM#wp5p^pmN<<8$^Wc2l@B1L2%b>+_#E%Wey+|SWAHI^}Pt=sGI9K?rSDB87bzBwrv zetY%X)X=DJ=@%-`ZLu`pj)~~! za>VCgJZy_K0(7p)KmO!qfip=oIrJj2A#xB@Zm6_UGTWhg-V4Qheh^=KkrzF1LW|@3 zh>oTGK)ZfI2}G*~`O*XI^wgVW5GXh{ea8gE->4uM;#xW}0teSXgT;6>QNn z0@9^v%uPpmrV$=kqmC(b4ofe4Kv87%M}lK1@ibT4vS&P+^ErG!o=N|{^{vh zn_IN)PV;t+=YsXandDoJmEtxpB>YdCdOYM>l#Z(cE@PT}qkgPeb!1#ZvD6021MWog zT1D!gg;c#&&Vfu-5ND*snfm@-O)k2oDvzHYx{>E6UU|jcm%(BZyi+iwzEyAWJHk2& zt`CHj17khH!vIJE5mDlH6PDP^!n@LWX^>ddNC<3?EHD(~-Qxo%vsqlm0)J~4g6W4}`GV?>(Zsg`nd~Htx$qOJ*VhgO3N;zg1!Ua`&P6rahcFlF5fHJjx=_!B*^ZR{< z;meme0QcB2PPIF#`F8*#_Gnd70o#Qv{h~cqX`t#I z7$*3Si6ojFveT>BCt`7bEs*nM7Sqs*LNzg^jj$2{KZQBHhd8KDIkH3-fh6 z5JEo2ScX6nB(NJu`G{Q5el(Fx{0o`?ZsX+kLOpf&vNLvk&WlKUyVqJ430}3t=%Gmc zJ}MH9=A0w5jC~{NM&}&sC(lYKJ0wO{?A9C+XHl>hy{3br0XY@Q%golTSGpX ziKK(Uf=KZ8>P}dRC*88=^Asi2OR^h!|7TEK0DVXMB?k}d zQwQ`Oi)w_!ZX9lyWM&f0`C^AHa-!m!Pe3YL1!R&OAo<-^GB#}j$$eT77CXn28@($e z-zPfmI&15(X}U`)C}MxIGu01mHIR!OAGOAb>x0Qm`hg8UYuYle-RH^Oe}OfmX8Cba zD`R9`Sm>S&;Wgp{ZbA%=;}c-4m_LWKrq@iCh)YwT#gd3G$4Jt=W8v4J52~E#%zqxm zo&VLaIhYI`X95H!di;-1tW`Qh!{4Oj7j^AK4I0l%6$wAIz}5gv54c(l5Zw;@_u#A| zTHkX3Xe7P0;(IiMNlx1q6YxzRAEZM`AIP@qLA-PiPjRX&Z*88!UbEcBB5^g{XFOq{UZD~Kr_t7{Or~;z*JUx7X0K9hWD4u*F5|! zC0{3d<428tu)`96d8keV7i6)ilMc}Ss=x4;3hMmm1#LC!873cD`|D{QMH*C$YSG*_F;hqDrP-ItI>q^7zuz#Hz*0@vh<^pYyA>MnmgiIN%O8oNswyH*R2W_(KBqp?1lu*OZ{eilX@+QpM_ zSW&G~^Su;}vTLRaB2zpx%Oeqyc)+5$l!OebKPxd;l7UVgeTe$jA?<=dJtad^!8YgzzpvZ%QfaoroNZ4)ttUUMO1o59Q)Q?AmbGJ4%E470hGaNJ8se_I_}a z>D|Iq)}K+@y=$?eDf%@x>?*7Ljo^81f}R59EV!SCIa((1V*in}e@$w1+9@}3lO zM{*Q`FSC}H6@}H2m<1)Z;kVUcIh%@czUR;Im^0Gq zAG*y6?z_R4?jlDTrzEJ} z==pqI6mmTK*5Te%1G5k_EB(~zxyA0yD;#iy*~?YS(jSfrJg1jbw<8}$aV72Xine)? zWEO0I9_szMGF|pbp6OGPr^o;@QY-tEbY*aRzlN=O$DeNJL4AoDGa7@*YT)kQHJVG+ zDpa+IP|HUjT|G`jewC(QYFT0qO}r_=TbWI_aEy6)ACoTOuL}hnjmx*_ARp_iT4I`@ ziu72XIf%UmGv|){DDKDRp)K0tm$wJ3$tO$ps1Utm6|UY-)uy0h4nSgCI$?ocNOPKw z^Zp4Jpa27fG1lb4uI6z`lA=XhS&R4_tkvD8V4lCtGf8gnq)eXN{Lnz)o@8T~iu$ag z>bs}U{R4qzig`ab_m~BxW|dS)aTN5a!b|Cu1|*;U#E7Fm`UZW2HLGRr`L|^L&`t_5 zAIwD3OZLDmCBw$?^0a~D*mw}9c1Abtl&tPunWFk2hMotY#`E?bO}#kXJ@j|_SJ)~b zTumgk{7fON9xrdg93)ns*>r=Kw~mz>t|qx89ICIQo8Q(Hpn1ZN=v5=_(4l?)EvTUB z1}ASKyN*TtRaMW>9!dvdSca9y#_tfJt_|WwTLSFIaZc$B#XsbN=VV@;74QBaR=sHu z6Hc!bB}7aRC4_~(GxSCYJw)Ge!Xt$Um7?4+pDNIy$%BprM?U#Mp1k%L*iE@S+dDqHcm0%J5 z@M299h_n8Kfqz_@;NOfjZdV00u1gkeeULGuq%OjF9;DDy^aFw1hSRLcB}=`kveoH9 zL?NM6G;3NCeitjP%6E4Q_m}F?POPMe-f{+6_A(@h|Nbyk;_mVNSwaE8|NhSOtEMd= z&JccoD2nAE6$W?fym(c^_40i)T*`@uq39(QEzX2^q^g<^`dQO3IQc*~fGA$nSA(j_ z%7=M`w)EKGq-4)8%Q}@ksrzQ_J3~eLR37G&Dx`PjI(!g#VxKDyM~K+@)`+;}ypSLm z)X~i8UJX*0Fi6p+Naan=a5I;OlP?orHCPpdZ6oHyqmactk*u*;BrWl=Q1VnAC))-z zH%YJN#4INB)aEOqc}UjxhOAlG5E@6zvKN}*WLtl}8hk3O$|(M4WewOM{t@9ojTWkf3G zQS#QMagrlV)|@Srkn2I@r`$3$UCJVbwxe$%p7 z5-Ur1fT^zEt;P3e$~i5@?K*>iS|-tch4+0(zkQV>(SLO(jncH85$xBy%LyB%pbbn{ z!&ts&hP_K&Yd#S}&Ahff%}@bt#_z}SWp!-At+G~6U2uo|D5LHnIKHkMvNC`>)(B!Cc{D4zdK=@r{2`Nxxd5 z){ox&2p?=xD0}yxpwovYtQF;jWuFCNSy^(G>&E|SPHZlCWQC`f*W$+7vt8t_aXn58 ztYW0Tzxv>gguk{)Ljz*i3h6k~^((Cpr#NlxJ*v9|Z@eGZeb3GxV;?*K*q?*Qe$SsGpX^Dx-PA#`W(jNg#QaON}AswRhWj`NL&g(%uzQ?3d%X}f~= zBftgkH+3MepnGGTC!=jU_Wc=7m@!uDg%G6h?CG}br?&GQK z_RHTnqYQ|~(*ituDLWBHJiJ_1ABg@#raCH&R*>_N^xu$JDrw=Dz3LAH77wz$R5q>bcdV z1r4afJD;@6%589$;FGJ)uiyyh@%f53@;SXo+K#joQ@j55zV@l3;B2=#Kk!nQaKxQd z+x(gJ6a9OOtmB=h%s~sZlGH9f-vgEYVE+qL@zy;R>CzNTZ!cj_Ip31pfWNwNk|2(g zC4{!lT$g!oxuN6OQ2W7E0H;~=Ji&39ad1%`A*7(R*^%*#LCCxQ{OH3mu1JI2)iwqH zTno%msXc#h<1{XcJNDsk1pL+9wXMwz4*$K@j(@F6+u)fsJ(MX{@lNz_K8Kp5@5=0@ z2!GS?iP7W0+>`i(d*HCs74Bi6-RHFi?Dt-NYxm^}*&j4Pa2oo%uHoD7-~;7WUxuH| zA`T_dQ?3U5Ek6PWcivwV9~3OF?+cbk?QJE3-w7tln%fbf+U4KlIa*PEa=S+ItJJ#U zMQ?T{Pv1q`)~aYTAZId{hx*?fv>x+>TsbV3>|hwtivHlYHJ}kSsRu4hoE3iiPdv-N z@qc(0*Pq*J9c{5XkBXbFxjB73iIhLDMP>yF^tG&mzD{&pxFEkw*$GQ<2uZ`Jk)xEZ z;<=xtOQbtIJn;H9sA{%f-pV#6m^ekMjzHhq`wA!lgWRKHEemrBGAPj~MwnVxkd2&6 zHCIAgmPU_i4NzF#Mys3mUDXD_(-Xakwj%5EsNS0yT9y7RAK%(>oV#=b7(HRzpt|Jj z>BC)DKE4tj{gy%Hw_ZX_C)|j8wG($Yv)Vw@tH~23ZQ3g0?VuUraSN9C$mrVo3n6fw zv;fLCZ3?xx6kIL&aC>^m@#=X|q!C_y!zmdCnUMn92_*$aA(fpA9jsNF?L^~NuQ?dv zMwdfOKFfkliq$4Ezt&zuEUtzzvPt>XC*arm9HBYJ;-QAU?2Q4pItehC>yr&cx zF4rD;N%ZGeF(~3((Du`?wM+AA-7iDkWf1RjuU3rH=b&43{*tH2KP?mCRkvIRgAQ6*V+WR*W7= zx?mUQgz)V=$#Bi?F9#AZyZT{xG<6*N#MiN(QoSR<}!=A@=(MQ^?L-}`1@QQS+4 zW9OQ!p`N8&JO&C$*;Y|jqRVLEyl z*sDR`DI$_lT-Db+i_7O1w2?~wq)ak4iU@UW{w!ZLWyQ!_PcekfgxNL)~w%Bjqng0ee;A!%r=pSIna!OTrCPVzDO{B zTZ&FM7Ffa8c8tSEVobWKb%0rjg(d8l+KK@W-JKdLh*1WkdtCem+~(cr-#(d z59E*fkYG#TWkw`p02KH?`YJ_$6@lpg6GJvBYqr7VDwP!qRH?2M@;f?xEs|=nI)yv< z0Ol#-%pNsc=%cH#cE$ZiqYCI;u}Ir)*h7e)@|}m$rqo=z+F2qN%2+$0Ha{?XE!wko zB%YK@7YW0T??rHZQPWzr`(?2a!78bRxLmG5-!}}nTUW?(aQlR=*T`G|n0P=dA1!4* zl4~So)IJ(BMo|*~JU%dMLFKeItLY)vr%Jke;+zLQ#&~2Vh~hZmuL6xEOdpSrzF%Qi z<|>wHU%fRWM*{dVQ6LlnndRp+7(E^7ROinO)lCC9~}Bes;CcZ{tE)e|DcxrYO^dDo|#F zMuZ+CUsI2T67|{58e8hCFo%i|by#{@+6?i=l}ZX^JX6gvzq1^-sEB|m-gK-mtd?!x zb>#0KH$^oKIv;!F@H>Nf-dorj=Y2M_#eSSfUHwpi39hJyQM5FQ7^{*rKLZLRHA21z zT&A1m5;)6DlJn?s&V4nuWYDk!^4I!{lb9|y8sKBhIK6fot!6&M{Q1GoK zO^s=B4Y&r$1R{ED+@Rxbx?SV+iIRj@0v6eDHdP_Hy5*MZ(!tEAbKENmyLI-)!X5|W zt!WmJ@M_t7Rb7n}KYs`3;m7yTeA^P2#4uurpnB!BjM0Y=vqyJX7hET2l#bq` z^9E$1B-MGy;(Q(6niIib^M|mGA5@}jBrgZio<`o)+S80f89ty&$05|V7VlX0OI}3L zp7oI^<*n!poz=GkAjlwd_~uoN*;4z>F=^hws}Vz&MB`@Nbp}R3#a-6nCoQ7NGzSC_nFPwKP?P`26DW|iHT*J+69yO zoFQK1&B5;YlqoWtID%37INcLL=bnY zK}n%%+h!D*$DyWWV2A=#o~9oDt-zcO7bx78Vwq2+nvl#$@CChdA=OBtO;=Kds5$^} z6ktr>1;c;tOad;Xp_pR-fU@MUKTEpCeJYDw|Io3cFWMAIj0^ujFYtLj|6iG1LNr750v_oYv9SWh;Wk3U9fYZRZqDaSt6}Hk1+5ItR^`P*Z=Uo z`KMcaBDqo-rUO`wG=|%7U$_FnS5(#?g=xBaJchIXi|_ zDe7$pZ(y!JjNuDT~KNt6jEDNdMftH)-gG~TMIW^gG>34zu1{_@i AG5`Po literal 0 HcmV?d00001 diff --git a/doc/workbook/basics/WSF_SERVICE_LAUNCHER_FCGI.png b/doc/workbook/basics/WSF_SERVICE_LAUNCHER_FCGI.png new file mode 100644 index 0000000000000000000000000000000000000000..b42d4b96eab5a19e8793c14ae5f032072c8bcc57 GIT binary patch literal 9552 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 E9||hX#sB~S literal 0 HcmV?d00001 diff --git a/doc/workbook/basics/WSF_SERVICE_LAUNCHER_NINO.png b/doc/workbook/basics/WSF_SERVICE_LAUNCHER_NINO.png new file mode 100644 index 0000000000000000000000000000000000000000..ecca100efcd47b3cf630e6f526aa225dfce1052e GIT binary patch literal 9523 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 z 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 ## A simple Service to Generate Plain Text. diff --git a/doc/workbook/basics/simple/simple.ecf b/doc/workbook/basics/simple/simple.ecf index 5f3b30d7..3d9149d0 100644 --- a/doc/workbook/basics/simple/simple.ecf +++ b/doc/workbook/basics/simple/simple.ecf @@ -37,6 +37,14 @@ + + + + + + From 5255b15fa9db5be728b6ce5fca038970b04ede69 Mon Sep 17 00:00:00 2001 From: Javier Velilla Date: Mon, 29 Jun 2015 18:36:44 -0300 Subject: [PATCH 20/36] Update basics.md --- doc/workbook/basics/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index 3f2aa197..d4d9b987 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -95,7 +95,7 @@ on fcgi (or cgi) using Apache or another popular web server. **WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is a marker interface in EWF. And also provides a way to launch our application using different kind of connectors. The class **WSF_DEFAULT_SERVICE_I**, inherit from **WS_LAUNCHABLE_SERVICE** and has a formal generic that should conform to **WSF_SERVICE_LAUNCHER [WSF_EXECUTION]**. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing one of the possible options. -![Nino Launcher](/doc/workbook/basics/WSF_SERVICE_LAUNCHER_NINO.png" Nino Hierarchy") +![Standalone Launcher](/doc/workbook/basics/WSF_SERVICE_LAUNCHER_STANDALONE.png "Standalone Hierarchy") Other connectors: **WSF_STANDALONE_SERVICE_LAUNCHER** From b16e4aa57018cbddf0aa9882a4a6e835f9f22f57 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Mon, 29 Jun 2015 19:03:54 -0300 Subject: [PATCH 21/36] Updated basic documentation --- doc/workbook/basics/basics.md | 59 ++++++------------- .../basics/simple/application_execution.e | 1 - 2 files changed, 17 insertions(+), 43 deletions(-) diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index 3f2aa197..b6c520ab 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -113,8 +113,6 @@ Im the **APPLICATION_EXECUTION** class class you will need to implement implemen The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created per request, with two main attributes request: ```WSF_REQUEST``` and response: ```WSF_RESPONSE```. - - ## A simple Service to Generate Plain Text. @@ -122,45 +120,34 @@ Before to continue, it is recommended to review the getting started guided. ```eiffel class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - end + make feature -- Basic operations - execute (req: WSF_REQUEST; res: WSF_RESPONSE) + execute -- Execute the incomming request do -- To send a response we need to setup, the status code and -- the response headers. - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) - res.put_string ("Hello World") + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) + response.put_string ("Hello World") end - end + ``` ##### Source code The source code is available on Github. You can get it by running the command: -```git clone https://github.com/EiffelWebFramework/ewf_examples.git``` +```git clone https://github.com/EiffelWebFramework/ewf.git``` -The example of simple service that generate plain text response is located in the directory $PATH/ewf_examples/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command: +The example of simple service that generate plain text response is located in the directory $PATH/ewd/doc/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command: ```estudio -config simple.ecf -target simple_nino``` @@ -173,37 +160,25 @@ To generate HTML, it's needed ```eiffel class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - end + make feature -- Basic operations - execute (req: WSF_REQUEST; res: WSF_RESPONSE) + execute -- Execute the incomming request do -- To send a response we need to setup, the status code and -- the response headers. - res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) - res.put_string (web_page) + response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>) + response.put_string (web_page) end - web_page: STRING = "[ @@ -221,9 +196,9 @@ end ##### Source code The source code is available on Github. You can get it by running the command: -```git clone https://github.com/EiffelWebFramework/ewf_examples.git``` +```git clone https://github.com/EiffelWebFramework/ewf.git``` -The example of the service that generates HTML is located in the directory $PATH/ewf_examples/workbook/basics/simple_html, where $PATH is where you run ```git clone``` . Just double click on the simple_html.ecf file and select the simple_html_nino target or if you prefer the command line, run the command: +The example of the service that generates HTML is located in the directory $PATH/ewf/doc/workbook/basics/simple_html, where $PATH is where you run ```git clone``` . Just double click on the simple_html.ecf file and select the simple_html_nino target or if you prefer the command line, run the command: ```estudio -config simple_html.ecf -target simple_html_nino``` diff --git a/doc/workbook/basics/simple/application_execution.e b/doc/workbook/basics/simple/application_execution.e index 28b1e2f3..58917ef8 100644 --- a/doc/workbook/basics/simple/application_execution.e +++ b/doc/workbook/basics/simple/application_execution.e @@ -22,5 +22,4 @@ feature -- Basic operations response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>) response.put_string ("Hello World") end - end From f23aeb64129fbbdd2817d864f028150d154e50a9 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 30 Jun 2015 08:42:29 -0300 Subject: [PATCH 22/36] Updated Workbook basic documentation. --- doc/workbook/basics/basics.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md index 2547729c..f5706441 100644 --- a/doc/workbook/basics/basics.md +++ b/doc/workbook/basics/basics.md @@ -30,9 +30,9 @@ end ``` The class ```APPLICATION``` inherit from -```WSF_DEFAULT_SERVICE [G ->WSF_EXECUTION create make end]``` it will be responsible to launch the service an set optional options. +```WSF_DEFAULT_SERVICE [G ->WSF_EXECUTION create make end]``` it will be responsible to launch the service and set optional options. -The class ```APPLICATION_EXECUTION``` is an implementation ```WSF_EXECUTION``` interface, which is instantiated for each incoming request. +The class ```APPLICATION_EXECUTION``` is an implementation of ```WSF_EXECUTION``` interface, which is instantiated for each incoming request. ```eiffel class @@ -86,10 +86,10 @@ end ``` The **WSF_REQUEST** gives access to the incoming data; the class provides features to get information such as request method, form data, query parameters, uploaded files, HTTP request headers, and hostname of the client among others. + The **WSF_RESPONSE** provides features to define the response with information such as HTTP status codes (10x,20x, 30x, 40x, and 50x), response headers (Content-Type, Content-Length, etc.) and obviously the body of the message itself. -**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi, or nino or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For producti -on fcgi (or cgi) using Apache or another popular web server. +**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi,nino or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server. ![Launcher Hierarchy](/doc/workbook/basics/Launcher Hierarchy.png "Launcher Hierarchy") @@ -105,9 +105,9 @@ Other connectors: A basic EWF service inherits from **WSF_DEFAULT_SERVICE**, which has a formal generic that should conform to **WSF_EXECUTION** class with a `make' creation procedure, in our case the class **APPLICATION_EXECUTION**. - The **APPLICATION_EXECUTION** class inherits from **WSF_EXECUTION** interface, which is instantiated for each incoming request. **WSF_EXECUTION** inherit from **WGI_EXECUTION** which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```. -Im the **APPLICATION_EXECUTION** class class you will need to implement implement the **execute** feature, get data from the request *req* and write the response in *res*. + +In the **APPLICATION_EXECUTION** class class you will need to implement implement the **execute** feature, get data from the request *req* and write the response in *res*. ![Execution Hierarchy](/doc/workbook/basics/APPLICATION_EXECUTION.png "Application Execution ") @@ -116,7 +116,7 @@ The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created ## A simple Service to Generate Plain Text. -Before to continue, it is recommended to review the getting started guided. +Before to continue, it is recommended to review the getting started guided. In the example we will only shows the implementation of the WSF_EXECUTION interface. ```eiffel class From 01f649fd8888c3f9c6f84f0adce3da88d936337f Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 30 Jun 2015 08:57:00 -0300 Subject: [PATCH 23/36] Updated: workbook headers document. Removed: unnecessary files. --- doc/workbook/SERVICE_TEMPLATE.png | Bin 13437 -> 0 bytes doc/workbook/basics/reading_request_data.md | 0 doc/workbook/handling_request/headers.md | 59 +++++++------------- 3 files changed, 20 insertions(+), 39 deletions(-) delete mode 100644 doc/workbook/SERVICE_TEMPLATE.png delete mode 100644 doc/workbook/basics/reading_request_data.md diff --git a/doc/workbook/SERVICE_TEMPLATE.png b/doc/workbook/SERVICE_TEMPLATE.png deleted file mode 100644 index f8eecdbd84c70a08892492a5d938f7b5be926eb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13437 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 diff --git a/doc/workbook/basics/reading_request_data.md b/doc/workbook/basics/reading_request_data.md deleted file mode 100644 index e69de29b..00000000 diff --git a/doc/workbook/handling_request/headers.md b/doc/workbook/handling_request/headers.md index b7708689..a49a7440 100644 --- a/doc/workbook/handling_request/headers.md +++ b/doc/workbook/handling_request/headers.md @@ -1,4 +1,4 @@ -Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) #Handling Requests: Headers @@ -165,35 +165,26 @@ included in the Referer header when the browser requests Web page B. * [User-Agent](https://httpwg.github.io/specs/rfc7231.html#header.user-agent) - The "User-Agent" header field contains information about the user agent of the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use or device. +**Note**: the example shows the **WSF_EXECUTION** implementation, that will be used by the service launcher. + #### Building a Table of All Request Headers -The following [EWF service](./headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives. +The following [EWF service](/doc/workbook/headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives. + The service accomplishes this task by calling ```req.meta_variables``` feature to get an ```ITERABLE [WSF_STRING]```, an structure that can be iterated over using ```across...loop...end```, then it checks if the name has the prefix ```HTTP_``` and if it is true, put the header name and value in a row. (the name in the left cell, the value in the right cell). The service also writes three components of the main request line (method, URI, and protocol), and also the raw header. ```eiffel class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - set_service_option ("verbose", true) - end + make feature -- Basic operations @@ -293,32 +284,21 @@ To be completed. #### Detecting Browser Types -The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](./headers/browser_name/application.e) that sends browser-specific responses. +The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/doc/workbook/headers/browser_name/application.e) that sends browser-specific responses. + The examples uses the ideas based on the [Browser detection using the user agent](https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent) article. Basically the code check if the header user_agent exist and then call the ```browser_name (a_user_agent: READABLE_STRING_8): READABLE_STRING_32``` feature to retrieve the current browser name or Unknown in other case. ```eiffel class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - set_service_option ("verbose", true) - end + make feature -- Basic operations @@ -329,8 +309,8 @@ feature -- Basic operations l_page_response: STRING l_rows: STRING do - create l_page_response.make_from_string (html_template) - if req.path_info.same_string ("/") then + create l_page_response.make_from_string (html_template) + if req.path_info.same_string ("/") then -- retrieve the user-agent if attached req.http_user_agent as l_user_agent then @@ -404,7 +384,7 @@ end ``` Let see some results, we will show the html returned -Internet Explorer +**Internet Explorer** --- ```

EWF service example: Showing Browser Dectection Using User-Agent


@@ -414,7 +394,7 @@ Internet Explorer

Enjoy using Internet Explorer

``` -Chrome +**Chrome** --- ```

EWF service example: Showing Browser Dectection Using User-Agent


@@ -448,10 +428,11 @@ As an exercise, try to write a similar service to retrieve the OS family using t * [SERVER_PROTOCOL](https://tools.ietf.org/html/rfc3875#section-4.1.15) * [SERVER_SOFTWARE](https://tools.ietf.org/html/rfc3875#section-4.1.16) -An [EWF service](./headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables. +**Example** +An [EWF service](/doc/workbook/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables. -Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) From efd80c1287738e88b90f811cca0f71bbeb84e3d0 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 30 Jun 2015 09:00:47 -0300 Subject: [PATCH 24/36] Updated workbook form document --- doc/workbook/handling_request/form.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/doc/workbook/handling_request/form.md b/doc/workbook/handling_request/form.md index 47da6767..c72772b6 100644 --- a/doc/workbook/handling_request/form.md +++ b/doc/workbook/handling_request/form.md @@ -1,4 +1,4 @@ -Nav: [Workbook](../workbook.md) | [Basic Concepts] (/workbook/basics/basics.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md) +Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) #Handling Requests: Form/Query Data @@ -285,25 +285,23 @@ and a simple message. ``` The source code is available on Github. You can get it by running the command: -```git clone https://github.com/EiffelWebFramework/ewf_examples.git``` +```git clone https://github.com/EiffelWebFramework/ewf.git``` -The example is located in the directory $PATH/ewf_examples/workbook/upload_file where $PATH is where you run git clone. +The example is located in the directory $PATH/ewf/doc/workbook/upload_file where $PATH is where you run git clone. ## Examples The source code is available on Github. You can get it by running the command: -```git clone https://github.com/EiffelWebFramework/ewf_examples.git``` +```git clone https://github.com/EiffelWebFramework/ewf.git``` -The GET example is located in the directory $PATH/ewf_examples/workbook/form/get, and the post example is located in the directory $PATH/ewf_examples/workbook/form/post where $PATH is where you run git clone . To run open it using Eiffel Studio or just run theg following command +The GET example is located in the directory $PATH/ewf/doc/workbook/form/get, and the post example is located in the directory $PATH/ewf_examples/workbook/form/post where $PATH is where you run git clone . To run open it using Eiffel Studio or just run theg following command ```estudio -config .ecf -target ``` >Note: replace and with the corresponding values. - - -Nav: [Workbook](../workbook.md) | [Basic Concepts] (/workbook/basics/basics.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md) +Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) From 2c745c63d3ad5ac927cab74f88304e46e1041c3c Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 30 Jun 2015 09:21:12 -0300 Subject: [PATCH 25/36] Updated workbook: generating response, handling cookies and headers documents. --- .../generating_response.md | 38 ++++--------------- .../handling_cookies/handling_cookies.md | 22 +++-------- doc/workbook/handling_request/headers.md | 6 +-- 3 files changed, 16 insertions(+), 50 deletions(-) diff --git a/doc/workbook/generating_response/generating_response.md b/doc/workbook/generating_response/generating_response.md index 1c2609b3..4d63cdfd 100644 --- a/doc/workbook/generating_response/generating_response.md +++ b/doc/workbook/generating_response/generating_response.md @@ -1,5 +1,5 @@ -Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md) | [Handling Cookies](/workbook/handling_cookies/handling_cookies.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md) ## EWF Generating Response @@ -164,24 +164,13 @@ Note: use ```res.set_status_code({HTTP_STATUS_CODE}.bad_request)``` rather than Basic Service that builds a simple web page to show the most common status codes ```eiffel class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - end + make feature -- Basic operations @@ -321,24 +310,13 @@ note revision : "$Revision$" class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - end + make feature -- Basic operations @@ -1018,4 +996,4 @@ There are four categories for response header fields: -| [Handling Requests: Header Fields](/workbook/handling_request/headers.md) | [Handling Cookies](/workbook/handling_cookies/handling_cookies.md) +Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md) diff --git a/doc/workbook/handling_cookies/handling_cookies.md b/doc/workbook/handling_cookies/handling_cookies.md index cfac299d..f1de9bdc 100644 --- a/doc/workbook/handling_cookies/handling_cookies.md +++ b/doc/workbook/handling_cookies/handling_cookies.md @@ -1,4 +1,4 @@ -Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md) +Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) # Handling Cookies @@ -146,25 +146,13 @@ note revision : "$Revision$" class - APPLICATION + APPLICATION_EXECUTION inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end + WSF_EXECUTION create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service. - do - set_service_option ("port", 9090) - set_service_option ("verbose",True) - end + make feature -- Basic operations @@ -297,4 +285,4 @@ end ``` -Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md) +Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) diff --git a/doc/workbook/handling_request/headers.md b/doc/workbook/handling_request/headers.md index a49a7440..bba056ed 100644 --- a/doc/workbook/handling_request/headers.md +++ b/doc/workbook/handling_request/headers.md @@ -170,7 +170,7 @@ included in the Referer header when the browser requests Web page B. #### Building a Table of All Request Headers -The following [EWF service](/doc/workbook/headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives. +The following [EWF service](/doc/workbook/handling_request/headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives. The service accomplishes this task by calling ```req.meta_variables``` feature to get an ```ITERABLE [WSF_STRING]```, an structure that can be iterated over using ```across...loop...end```, then it checks if the name has the prefix ```HTTP_``` and if it is true, put the header name and value in a row. (the name in the left cell, the value in the right cell). @@ -284,7 +284,7 @@ To be completed. #### Detecting Browser Types -The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/doc/workbook/headers/browser_name/application.e) that sends browser-specific responses. +The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/doc/workbook/handling_request/headers/browser_name/application.e) that sends browser-specific responses. The examples uses the ideas based on the [Browser detection using the user agent](https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent) article. Basically the code check if the header user_agent exist and then call the ```browser_name (a_user_agent: READABLE_STRING_8): READABLE_STRING_32``` @@ -429,7 +429,7 @@ As an exercise, try to write a similar service to retrieve the OS family using t * [SERVER_SOFTWARE](https://tools.ietf.org/html/rfc3875#section-4.1.16) **Example** -An [EWF service](/doc/workbook/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables. +An [EWF service](/doc/workbook/handling_request/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables. Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) From 412534d0be38f0a56f2abcd1ca565c20d35c9156 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 1 Jul 2015 21:43:54 +0200 Subject: [PATCH 26/36] Fixed compilation of all*-safe.ecf files. Corrected a few comments. --- .../ewsgi/connectors/standalone/src/httpd/httpd_server_i.e | 1 - .../connectors/standalone/src/wgi_standalone_output_stream.e | 2 +- tests/all-safe.ecf | 3 ++- tests/all-stable-safe.ecf | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e index b4115f1c..d3c236d7 100644 --- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e +++ b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e @@ -60,7 +60,6 @@ feature -- Access is_persistent_connection_supported: BOOLEAN = True -- Is persistent connection supported? - --| For now, disabled during dev. feature -- Callbacks diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e index 29c38300..ed4db3c4 100644 --- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e +++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e @@ -29,7 +29,7 @@ feature {NONE} -- Initialization last_target_call_succeed := True end -feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino +feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Server set_target (o: like target) do diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf index 6bf2afa2..d49d23d3 100644 --- a/tests/all-safe.ecf +++ b/tests/all-safe.ecf @@ -45,7 +45,8 @@ - + + diff --git a/tests/all-stable-safe.ecf b/tests/all-stable-safe.ecf index db1cc477..395ef4fd 100644 --- a/tests/all-stable-safe.ecf +++ b/tests/all-stable-safe.ecf @@ -40,7 +40,8 @@ - + + From 31557cfc338863ebf369d9162f40dc9cdc09a6aa Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 2 Jul 2015 10:50:41 +0200 Subject: [PATCH 27/36] Fixed WGI_HTTPD_REQUEST_HANDLER.process_rescue Fixed WGI_STANDALONE_OUTPUT_STREAM.is_available Added WGI_STANDALONE_RESPONSE_STREAM.is_persistent_connection_supported --- .../implementation/wgi_httpd_request_handler.e | 17 +++++++++++++---- .../src/wgi_standalone_output_stream.e | 2 +- .../src/wgi_standalone_response_stream.e | 11 ++++++++++- .../wsf_wgi_delayed_header_response.e | 16 +++++++++++++++- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e index 0ddecd18..3abd5220 100644 --- a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e +++ b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e @@ -87,6 +87,7 @@ feature -- Request processing else l_output.set_http_version (version) end + res.set_is_persistent_connection_supported ({HTTPD_SERVER}.is_persistent_connection_supported) res.set_is_persistent_connection_requested (is_persistent_connection_requested) req.set_meta_string_variable ("RAW_HEADER_DATA", request_header) @@ -111,22 +112,30 @@ feature -- Request processing end end + process_rescue (res: detachable WGI_RESPONSE) + local + s: STRING do if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.trace as l_trace then if res /= Void then if not res.status_is_set then res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void) end + create s.make_empty + s.append ("
")
+					s.append (html_encoder.encoded_string (l_trace))
+					s.append ("
") + if not res.header_committed then + res.put_header_text ("Content-Type: text/html%R%NContent-Length: " + s.count.out + "%R%N%R%N") + end if res.message_writable then - res.put_string ("
")
-						res.put_string (html_encoder.encoded_string (l_trace))
-						res.put_string ("
") + res.put_string (s) end res.push end end - end + end httpd_environment (a_socket: HTTPD_STREAM_SOCKET): STRING_TABLE [READABLE_STRING_8] local diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e index ed4db3c4..b3656cbb 100644 --- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e +++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_output_stream.e @@ -100,7 +100,7 @@ feature -- Status report -- -- for instance IO failure due to socket disconnection. do - Result := not last_target_call_succeed + Result := last_target_call_succeed end is_open_write: BOOLEAN diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e index d4863bde..ad19d07e 100644 --- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e +++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e @@ -23,6 +23,9 @@ feature -- Settings is_http_version_1_0: BOOLEAN -- Is associated request using HTTP/1.0 ? + is_persistent_connection_supported: BOOLEAN + -- Is persistent connection supported? + is_persistent_connection_requested: BOOLEAN -- Is persistent connection requested? @@ -34,6 +37,12 @@ feature -- Settings change is_http_version_1_0 := True end + set_is_persistent_connection_supported (b: BOOLEAN) + -- Set `is_persistent_connection_supported' to `b'. + do + is_persistent_connection_supported := b + end + set_is_persistent_connection_requested (b: BOOLEAN) -- Set `is_persistent_connection_requested' to `b'. do @@ -53,7 +62,7 @@ feature -- Header output operation create s.make_from_string (a_text) i := s.substring_index ("%NConnection:", 1) - if {HTTPD_SERVER}.is_persistent_connection_supported then + if is_persistent_connection_supported then -- Current standalone support persistent connection. -- If HTTP/1.1: -- by default all connection are persistent diff --git a/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e b/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e index 1b65b8f7..cb920fc3 100644 --- a/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e +++ b/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e @@ -9,6 +9,7 @@ class inherit WGI_FILTER_RESPONSE redefine + set_status_code, commit, put_character, put_string, @@ -74,6 +75,19 @@ feature {NONE} -- Implementation header_committed: header_committed end +feature -- Status setting + + set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) + -- Set response status code with custom `a_reason_phrase' if precised + -- Should be done before sending any data back to the client + do + if a_reason_phrase /= Void then + wsf_response.set_status_code_with_reason_phrase (a_code, a_reason_phrase) + else + wsf_response.set_status_code (a_code) + end + end + feature -- Status report message_writable: BOOLEAN = True @@ -116,7 +130,7 @@ feature -- Output operation end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software From af60a5719e139621f6c38f3425ce74a774c701f7 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 2 Jul 2015 13:06:38 +0200 Subject: [PATCH 28/36] Updated eiffelstudio locations for EWF libraries. --- tools/install_ewf.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/install_ewf.bat b/tools/install_ewf.bat index 403d95b1..484db08d 100644 --- a/tools/install_ewf.bat +++ b/tools/install_ewf.bat @@ -90,11 +90,11 @@ echo Install library: content_negotiation %COPYCMD% %TMP_DIR%\library\network\protocol\content_negotiation %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation echo Install library: http_authorization %SAFE_MD% %TMP_CONTRIB_DIR%\library\network\authentication -%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\network\authentication\http_authorization +%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization echo Install library: openid %SAFE_MD% %TMP_CONTRIB_DIR%\library\security -%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\security\openid +%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\web\authentication\openid echo Install library: uri_template %COPYCMD% %TMP_DIR%\library\text\parser\uri_template %TMP_CONTRIB_DIR%\library\text\parser\uri_template From 33150e34d623e94ddb8a8449f20ea9e4088a62be Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 2 Jul 2015 15:11:33 +0200 Subject: [PATCH 29/36] Reverted previous changed related to redefinition of set_status_code which was against existing assertions. --- .../wsf_wgi_delayed_header_response.e | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e b/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e index cb920fc3..b5aeb6fc 100644 --- a/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e +++ b/library/server/wsf/src/implementation/wsf_wgi_delayed_header_response.e @@ -9,7 +9,6 @@ class inherit WGI_FILTER_RESPONSE redefine - set_status_code, commit, put_character, put_string, @@ -75,19 +74,6 @@ feature {NONE} -- Implementation header_committed: header_committed end -feature -- Status setting - - set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) - -- Set response status code with custom `a_reason_phrase' if precised - -- Should be done before sending any data back to the client - do - if a_reason_phrase /= Void then - wsf_response.set_status_code_with_reason_phrase (a_code, a_reason_phrase) - else - wsf_response.set_status_code (a_code) - end - end - feature -- Status report message_writable: BOOLEAN = True From 148518984e04068e3dc53230634d68253f85b50a Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 3 Jul 2015 10:02:56 +0200 Subject: [PATCH 30/36] Added the possibility to provide the sendmail location in NOTIFICATION_SENDMAIL_MAILER. Added NOTIFICATION_STORAGE_MAILER which allow to store the email in a storage (could be just output, file, database ...) Added SMTP implementation, based on EiffelNet SMTP_PROTOCOL. note: it is possible to exclude this by setting ecf variable "smtp_notification_email_disabled" to "True" this way help to manage dependencies, since the Eiffel Net library would not be included neither. Fixed Date header value computation. --- .../notification_email-safe.ecf | 16 +- .../notification_email/notification_email.e | 180 +++++++++++++++-- .../notification_email/notification_email.ecf | 14 +- .../notification_email/notification_mailer.e | 40 +++- .../notification_null_mailer.e | 34 ++++ .../notification_sendmail_mailer.e | 22 ++- .../notification_storage_mailer.e | 54 ++++++ .../smtp/notification_smtp_mailer.e | 181 ++++++++++++++++++ .../storage/notification_email_file_storage.e | 74 +++++++ .../storage/notification_email_storage.e | 38 ++++ 10 files changed, 625 insertions(+), 28 deletions(-) create mode 100644 library/runtime/process/notification_email/notification_null_mailer.e create mode 100644 library/runtime/process/notification_email/notification_storage_mailer.e create mode 100644 library/runtime/process/notification_email/smtp/notification_smtp_mailer.e create mode 100644 library/runtime/process/notification_email/storage/notification_email_file_storage.e create mode 100644 library/runtime/process/notification_email/storage/notification_email_storage.e diff --git a/library/runtime/process/notification_email/notification_email-safe.ecf b/library/runtime/process/notification_email/notification_email-safe.ecf index 01d95e0a..177c5441 100644 --- a/library/runtime/process/notification_email/notification_email-safe.ecf +++ b/library/runtime/process/notification_email/notification_email-safe.ecf @@ -1,5 +1,5 @@ - + @@ -11,8 +11,20 @@ + + + + + - + + + + + + + + diff --git a/library/runtime/process/notification_email/notification_email.e b/library/runtime/process/notification_email/notification_email.e index 4ca33864..5f835b82 100644 --- a/library/runtime/process/notification_email/notification_email.e +++ b/library/runtime/process/notification_email/notification_email.e @@ -2,9 +2,9 @@ note description : "[ Component representing an email ]" - author : "$Author$" - date : "$Date$" - revision : "$Revision$" + author : "$Author: jfiat $" + date : "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $" + revision : "$Revision: 97586 $" class NOTIFICATION_EMAIL @@ -14,15 +14,17 @@ create feature {NONE} -- Initialization - make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_body: like body) + make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_content: like content) -- Initialize `Current'. + require + well_formed_from_address: is_valid_address (a_from) + well_formed_to_address: a_to_address.has ('@') do initialize from_address := a_from subject := a_subject - body := a_body + content := a_content to_addresses.extend (a_to_address) - end initialize @@ -37,11 +39,36 @@ feature -- Access from_address: READABLE_STRING_8 + reply_to_address: detachable READABLE_STRING_8 + to_addresses: ARRAYED_LIST [READABLE_STRING_8] + cc_addresses: detachable ARRAYED_LIST [READABLE_STRING_8] + + bcc_addresses: detachable ARRAYED_LIST [READABLE_STRING_8] + subject: READABLE_STRING_8 - body: READABLE_STRING_8 + content: READABLE_STRING_8 + + additional_header_lines: detachable ARRAYED_LIST [READABLE_STRING_8] + -- Additional header lines. + + body: like content + obsolete + "Use `content' [June/2015]" + do + Result := body + end + +feature -- Status report + + is_valid: BOOLEAN + -- Is current email ready to be sent? + do + Result := is_valid_address (from_address) and + across to_addresses as ic all is_valid_address (ic.item) end + end feature -- Change @@ -50,13 +77,90 @@ feature -- Change date := d end + set_subject (s: READABLE_STRING_8) + -- Set `subject' to `s'. + do + subject := s + end + + set_content (s: READABLE_STRING_8) + -- Set `content' to `s'. + do + content := s + end + + set_from_address (add: READABLE_STRING_8) + require + well_formed_address: add.has ('@') + do + from_address := add + end + + add_cc_address (add: READABLE_STRING_8) + require + well_formed_address: add.has ('@') + local + lst: like cc_addresses + do + lst := cc_addresses + if lst = Void then + create lst.make (1) + cc_addresses := lst + end + lst.force (add) + end + + add_bcc_address (add: READABLE_STRING_8) + require + well_formed_address: add.has ('@') + local + lst: like bcc_addresses + do + lst := bcc_addresses + if lst = Void then + create lst.make (1) + bcc_addresses := lst + end + lst.force (add) + end + + add_header_line (a_line: READABLE_STRING_8) + require + well_formed_header_line: a_line.has (':') + local + lst: like additional_header_lines + do + lst := additional_header_lines + if lst = Void then + create lst.make (1) + additional_header_lines := lst + end + lst.force (a_line) + end + +feature -- Reset + + reset + do + reset_addresses + additional_header_lines := Void + end + + reset_addresses + -- Reset all addresses. + do + to_addresses.wipe_out + cc_addresses := Void + bcc_addresses := Void + end + feature -- Conversion message: STRING_8 do Result := header Result.append_character ('%N') - Result.append (body) + Result.append (content) Result.append_character ('%N') Result.append_character ('%N') end @@ -66,13 +170,14 @@ feature -- Conversion hdate: HTTP_DATE do create Result.make (20) + if attached reply_to_address as l_reply_to then + Result.append ("Reply-To: ") + Result.append (l_reply_to) + Result.append_character ('%N') + end Result.append ("From: ") Result.append (from_address) Result.append_character ('%N') - Result.append ("Date: ") - create hdate.make_from_date_time (date) - hdate.append_to_rfc1123_string (Result) - Result.append (" GMT%N") Result.append ("To: ") across to_addresses as c @@ -81,18 +186,67 @@ feature -- Conversion Result.append_character (';') end Result.append_character ('%N') + if + attached cc_addresses as l_cc and then + not l_cc.is_empty + then + Result.append ("Cc: ") + across + l_cc as c + loop + Result.append (c.item) + Result.append_character (';') + end + Result.append_character ('%N') + end + if + attached bcc_addresses as l_bcc and then + not l_bcc.is_empty + then + Result.append ("Bcc: ") + across + l_bcc as c + loop + Result.append (c.item) + Result.append_character (';') + end + Result.append_character ('%N') + end Result.append ("Subject: ") Result.append (subject) Result.append_character ('%N') + Result.append ("Date: ") + create hdate.make_from_date_time (date) + hdate.append_to_rfc1123_string (Result) + Result.append_character ('%N') + if attached additional_header_lines as l_lines and then + not l_lines.is_empty + then + across + l_lines as ic + loop + Result.append (ic.item) + Result.append_character ('%N') + end + end ensure Result.ends_with ("%N") end +feature -- Helpers + + is_valid_address (add: READABLE_STRING_8): BOOLEAN + -- Is `add' a valid email address? + do + -- FIXME: improve email validation + Result := add.has ('@') + end + invariant -- invariant_clause: True note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/runtime/process/notification_email/notification_email.ecf b/library/runtime/process/notification_email/notification_email.ecf index 80db0f22..353b3b42 100644 --- a/library/runtime/process/notification_email/notification_email.ecf +++ b/library/runtime/process/notification_email/notification_email.ecf @@ -11,8 +11,20 @@ + + + + + - + + + + + + + + diff --git a/library/runtime/process/notification_email/notification_mailer.e b/library/runtime/process/notification_email/notification_mailer.e index 01a16b2e..36be1ba2 100644 --- a/library/runtime/process/notification_email/notification_mailer.e +++ b/library/runtime/process/notification_email/notification_mailer.e @@ -2,9 +2,9 @@ note description: "[ Component responsible to send email ]" - author: "$Author$" - date: "$Date$" - revision: "$Revision$" + author: "$Author: jfiat $" + date: "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97586 $" deferred class NOTIFICATION_MAILER @@ -45,8 +45,40 @@ feature -- Basic operation deferred end +feature -- Error + + has_error: BOOLEAN + -- Previous operation reported error? + -- Use `reset_errors', to reset this state. + do + Result := attached last_errors as lst and then not lst.is_empty + end + + reset_errors + -- Reset last errors. + do + last_errors := Void + end + + last_errors: detachable ARRAYED_LIST [READABLE_STRING_32] + -- Last reported errors since previous `reset_errors' call. + + report_error (a_msg: READABLE_STRING_GENERAL) + -- Report error message `a_msg'. + local + lst: like last_errors + do + lst := last_errors + if lst = Void then + create lst.make (1) + last_errors := lst + end + lst.force (a_msg.to_string_32) + end + + note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/runtime/process/notification_email/notification_null_mailer.e b/library/runtime/process/notification_email/notification_null_mailer.e new file mode 100644 index 00000000..9707200d --- /dev/null +++ b/library/runtime/process/notification_email/notification_null_mailer.e @@ -0,0 +1,34 @@ +note + description: "Mailer that does nothing." + date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97588 $" + +class + NOTIFICATION_NULL_MAILER + +inherit + NOTIFICATION_MAILER + +feature -- Status + + is_available: BOOLEAN = True + -- + +feature -- Basic operation + + process_email (a_email: NOTIFICATION_EMAIL) + -- + do + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/runtime/process/notification_email/notification_sendmail_mailer.e b/library/runtime/process/notification_email/notification_sendmail_mailer.e index 2ea09397..e61f06de 100644 --- a/library/runtime/process/notification_email/notification_sendmail_mailer.e +++ b/library/runtime/process/notification_email/notification_sendmail_mailer.e @@ -2,9 +2,9 @@ note description : "[ NOTIFICATION_MAILER using sendmail as mailtool ]" - author: "$Author$" - date: "$Date$" - revision: "$Revision$" + author: "$Author: jfiat $" + date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97588 $" class NOTIFICATION_SENDMAIL_MAILER @@ -16,23 +16,29 @@ inherit end create - default_create + default_create, + make_with_location feature {NONE} -- Initialization + make_with_location (a_path: READABLE_STRING_GENERAL) + do + make (a_path, <<"-t">>) + set_stdin_mode (True, "%N.%N%N") + end + default_create do Precursor - make ("/usr/sbin/sendmail", <<"-t">>) + make_with_location ("/usr/sbin/sendmail") if not is_available then - make ("/usr/bin/sendmail", <<"-t">>) + make_with_location ("/usr/bin/sendmail") end - set_stdin_mode (True, "%N.%N%N") end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/runtime/process/notification_email/notification_storage_mailer.e b/library/runtime/process/notification_email/notification_storage_mailer.e new file mode 100644 index 00000000..89f28de2 --- /dev/null +++ b/library/runtime/process/notification_email/notification_storage_mailer.e @@ -0,0 +1,54 @@ +note + description: "Summary description for {NOTIFICATION_STORAGE_MAILER}." + author: "" + date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97588 $" + +class + NOTIFICATION_STORAGE_MAILER + +inherit + NOTIFICATION_MAILER + +create + make + +feature {NONE} -- Initialization + + make (a_storage: NOTIFICATION_EMAIL_STORAGE) + do + storage := a_storage + end + + storage: NOTIFICATION_EMAIL_STORAGE + +feature -- Status report + + is_available: BOOLEAN + -- + do + Result := storage.is_available + end + +feature -- Basic operation + + process_email (a_email: NOTIFICATION_EMAIL) + -- + do + storage.put (a_email) + if storage.has_error then + report_error ("Issue storing email.") + end + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/runtime/process/notification_email/smtp/notification_smtp_mailer.e b/library/runtime/process/notification_email/smtp/notification_smtp_mailer.e new file mode 100644 index 00000000..21f8b99d --- /dev/null +++ b/library/runtime/process/notification_email/smtp/notification_smtp_mailer.e @@ -0,0 +1,181 @@ +note + description: "[ + Notification mailer based on STMP protocol. + + Note: it is based on EiffelNet {SMTP_PROTOCOL} implementation, and may not be complete. + ]" + author: "$Author: jfiat $" + date: "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97586 $" + +class + NOTIFICATION_SMTP_MAILER + +inherit + NOTIFICATION_MAILER + +create + make, + make_with_user + +feature {NONE} -- Initialization + + make (a_smtp_server: READABLE_STRING_8) + do + make_with_user (a_smtp_server, Void, Void) + end + + make_with_user (a_smtp_server: READABLE_STRING_8; a_user: detachable READABLE_STRING_8; a_password: detachable READABLE_STRING_8) + -- Initialize `Current'. + local + i: INTEGER + do + i := a_smtp_server.index_of (':', 1) + if i > 0 then + smtp_host := a_smtp_server.substring (1, i - 1) + smtp_port := a_smtp_server.substring (i + 1, a_smtp_server.count).to_integer + else + smtp_host := a_smtp_server + smtp_port := 0 + end + username := a_user + initialize + end + + initialize + -- Initialize service. + local + l_address_factory: INET_ADDRESS_FACTORY + do + if attached username as u then + create smtp_protocol.make (smtp_host, u) + else + -- Get local host name needed in creation of SMTP_PROTOCOL. + create l_address_factory + create smtp_protocol.make (smtp_host, l_address_factory.create_localhost.host_name) + end + if smtp_port > 0 then + smtp_protocol.set_default_port (smtp_port) + end + reset_errors + end + + smtp_protocol: SMTP_PROTOCOL + -- SMTP protocol. + +feature -- Access + + smtp_host: READABLE_STRING_8 + + smtp_port: INTEGER + + username: detachable READABLE_STRING_8 + +feature -- Status + + is_available: BOOLEAN + do + Result := True + end + +feature -- Basic operation + + process_email (a_email: NOTIFICATION_EMAIL) + -- Process the sending of `a_email' + local + l_email: EMAIL + h: STRING + k,v: STRING + i: INTEGER + hdate: HTTP_DATE + do + create l_email.make_with_entry (a_email.from_address, addresses_to_header_line_value (a_email.to_addresses)) + if attached a_email.reply_to_address as l_reply_to then + l_email.add_header_entry ({EMAIL_CONSTANTS}.h_reply_to, l_reply_to) + end + + if attached a_email.cc_addresses as lst then + l_email.add_header_entry ({EMAIL_CONSTANTS}.h_cc, addresses_to_header_line_value (lst)) + end + if attached a_email.bcc_addresses as lst then + l_email.add_header_entry ({EMAIL_CONSTANTS}.h_bcc, addresses_to_header_line_value (lst)) + end + l_email.set_message (a_email.content) + l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, a_email.subject) + + create h.make_empty + create hdate.make_from_date_time (a_email.date) + hdate.append_to_rfc1123_string (h) + l_email.add_header_entry ("Date", h) + + if attached a_email.additional_header_lines as lst then + across + lst as ic + loop + h := ic.item + i := h.index_of (':', 1) + if i > 0 then + k := h.head (i - 1) + v := h.substring (i + 1, h.count) + l_email.add_header_entry (k, v) + else + check is_header_line: False end + end + end + end + + smtp_send_email (l_email) + end + +feature {NONE} -- Implementation + + addresses_to_header_line_value (lst: ITERABLE [READABLE_STRING_8]): STRING + local + l_need_separator: BOOLEAN + do + create Result.make (10) + l_need_separator := False + across + lst as ic + loop + if l_need_separator then + Result.append_character (',') + Result.append_character (' ') + else + l_need_separator := True + end + Result.append (ic.item) + end + end + + smtp_send_email (a_email: EMAIL) + -- Send the email represented by `a_email'. + local + retried: BOOLEAN + do + if not retried then + smtp_protocol.initiate_protocol + smtp_protocol.transfer (a_email) + smtp_protocol.close_protocol + if smtp_protocol.error then + report_error ("smtp_protocol reported an error.") + end + end + rescue + report_error ("smtp_protocol raised an exception.") + retried := True + retry + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/runtime/process/notification_email/storage/notification_email_file_storage.e b/library/runtime/process/notification_email/storage/notification_email_file_storage.e new file mode 100644 index 00000000..0923b622 --- /dev/null +++ b/library/runtime/process/notification_email/storage/notification_email_file_storage.e @@ -0,0 +1,74 @@ +note + description: "Store email in specific file (could also be stderr, ...)." + date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97588 $" + +class + NOTIFICATION_EMAIL_FILE_STORAGE + +inherit + NOTIFICATION_EMAIL_STORAGE + +create + make + +feature {NONE} -- Initialization + + make (a_output_file: FILE) + require + a_output_file_valid: a_output_file.exists + do + output := a_output_file + end + + output: FILE + +feature -- Status report + + is_available: BOOLEAN + -- Is associated storage available? + do + Result := output.exists and output.is_access_writable + end + + has_error: BOOLEAN + -- Last operation reported an error? + +feature -- Storage + + put (a_email: NOTIFICATION_EMAIL) + -- Store `a_email'. + local + retried: BOOLEAN + l_close_needed: BOOLEAN + do + if not retried then + has_error := False + if not output.is_open_write then + output.open_write + l_close_needed := True + end + output.put_string ("%N----%N" + a_email.message) + if l_close_needed then + output.close + else + output.flush + end + end + rescue + retried := True + has_error := True + retry + end + +;note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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/library/runtime/process/notification_email/storage/notification_email_storage.e b/library/runtime/process/notification_email/storage/notification_email_storage.e new file mode 100644 index 00000000..60e02a06 --- /dev/null +++ b/library/runtime/process/notification_email/storage/notification_email_storage.e @@ -0,0 +1,38 @@ +note + description: "Abtract interface of email storage." + date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $" + revision: "$Revision: 97588 $" + +deferred class + NOTIFICATION_EMAIL_STORAGE + +feature -- Status report + + is_available: BOOLEAN + -- Is associated storage available? + deferred + end + + has_error: BOOLEAN + -- Last operation reported an error? + deferred + end + +feature -- Storage + + put (a_email: NOTIFICATION_EMAIL) + -- Store `a_email'. + deferred + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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 From 4f8f17ad4811ca68a2f417485786c76d837cf331 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 3 Jul 2015 20:02:13 +0200 Subject: [PATCH 31/36] Fixed various compilation issues. Ensure the obsolete/v0 ecf has new UUID. --- .../tutorial/step_4/hello/src/hello_execution.e | 2 +- .../v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf | 2 +- .../v0/ewsgi/connectors/libfcgi/libfcgi.ecf | 2 +- .../v0/ewsgi/connectors/nino/nino-safe.ecf | 2 +- .../obsolete/v0/ewsgi/connectors/nino/nino.ecf | 2 +- .../obsolete/v0/wsf/connector/libfcgi-safe.ecf | 2 +- .../server/obsolete/v0/wsf/connector/libfcgi.ecf | 2 +- .../obsolete/v0/wsf/connector/nino-safe.ecf | 2 +- library/server/obsolete/v0/wsf/connector/nino.ecf | 2 +- .../obsolete/v0/wsf/default/libfcgi-safe.ecf | 2 +- .../server/obsolete/v0/wsf/default/libfcgi.ecf | 2 +- .../server/obsolete/v0/wsf/default/nino-safe.ecf | 2 +- library/server/obsolete/v0/wsf/default/nino.ecf | 2 +- .../server/obsolete/v0/wsf/wsf_extension-safe.ecf | 2 +- library/server/obsolete/v0/wsf/wsf_extension.ecf | 2 +- .../obsolete/v0/wsf/wsf_policy_driven-safe.ecf | 2 +- .../server/obsolete/v0/wsf/wsf_policy_driven.ecf | 2 +- .../obsolete/v0/wsf/wsf_router_context-safe.ecf | 2 +- .../server/obsolete/v0/wsf/wsf_router_context.ecf | 2 +- .../server/obsolete/v0/wsf/wsf_session-safe.ecf | 2 +- library/server/obsolete/v0/wsf/wsf_session.ecf | 2 +- .../server/obsolete/v0/wsf_html/wsf_html-safe.ecf | 2 +- library/server/obsolete/v0/wsf_html/wsf_html.ecf | 15 ++++++++------- .../lib/wizard/gui/graphical_wizard_application.e | 2 +- 24 files changed, 31 insertions(+), 30 deletions(-) diff --git a/examples/tutorial/step_4/hello/src/hello_execution.e b/examples/tutorial/step_4/hello/src/hello_execution.e index 82767817..8f95d03a 100644 --- a/examples/tutorial/step_4/hello/src/hello_execution.e +++ b/examples/tutorial/step_4/hello/src/hello_execution.e @@ -24,7 +24,7 @@ feature {NONE} -- Initialization setup_router do -- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello))) - map_uri_agent ("/hello", agent execute_hello) + map_uri_agent ("/hello", agent execute_hello, Void) -- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST) map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST) diff --git a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf index 62f9065a..75a3289c 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf index 7f3368d1..26a646d2 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/libfcgi/libfcgi.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf b/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf index 18ca2208..c29fdab5 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/nino/nino-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf b/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf index 8e222c2a..0f9c4c18 100644 --- a/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf +++ b/library/server/obsolete/v0/ewsgi/connectors/nino/nino.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf b/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf index f82815de..8a2544fe 100644 --- a/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/wsf/connector/libfcgi-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/connector/libfcgi.ecf b/library/server/obsolete/v0/wsf/connector/libfcgi.ecf index 7fbaa9c4..13d17544 100644 --- a/library/server/obsolete/v0/wsf/connector/libfcgi.ecf +++ b/library/server/obsolete/v0/wsf/connector/libfcgi.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/connector/nino-safe.ecf b/library/server/obsolete/v0/wsf/connector/nino-safe.ecf index 3538c5f8..d9eb9ea0 100644 --- a/library/server/obsolete/v0/wsf/connector/nino-safe.ecf +++ b/library/server/obsolete/v0/wsf/connector/nino-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/connector/nino.ecf b/library/server/obsolete/v0/wsf/connector/nino.ecf index 069bd8d0..0d020864 100644 --- a/library/server/obsolete/v0/wsf/connector/nino.ecf +++ b/library/server/obsolete/v0/wsf/connector/nino.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf b/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf index 2e137baa..91344373 100644 --- a/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf +++ b/library/server/obsolete/v0/wsf/default/libfcgi-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/default/libfcgi.ecf b/library/server/obsolete/v0/wsf/default/libfcgi.ecf index dfe174d5..e438fbd5 100644 --- a/library/server/obsolete/v0/wsf/default/libfcgi.ecf +++ b/library/server/obsolete/v0/wsf/default/libfcgi.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/default/nino-safe.ecf b/library/server/obsolete/v0/wsf/default/nino-safe.ecf index 6bad0d3f..235305a5 100644 --- a/library/server/obsolete/v0/wsf/default/nino-safe.ecf +++ b/library/server/obsolete/v0/wsf/default/nino-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/default/nino.ecf b/library/server/obsolete/v0/wsf/default/nino.ecf index 0530a122..a3f33bb7 100644 --- a/library/server/obsolete/v0/wsf/default/nino.ecf +++ b/library/server/obsolete/v0/wsf/default/nino.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf b/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf index e488c587..5553c2f9 100644 --- a/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_extension-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_extension.ecf b/library/server/obsolete/v0/wsf/wsf_extension.ecf index f6370e83..0691443d 100644 --- a/library/server/obsolete/v0/wsf/wsf_extension.ecf +++ b/library/server/obsolete/v0/wsf/wsf_extension.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf b/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf index 70e8e2ea..8670e863 100644 --- a/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_policy_driven-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf b/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf index 347334fc..ae2e26c3 100644 --- a/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf +++ b/library/server/obsolete/v0/wsf/wsf_policy_driven.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf b/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf index f56451af..12c3ee77 100644 --- a/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_router_context-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_router_context.ecf b/library/server/obsolete/v0/wsf/wsf_router_context.ecf index 5edfb081..fb0d707f 100644 --- a/library/server/obsolete/v0/wsf/wsf_router_context.ecf +++ b/library/server/obsolete/v0/wsf/wsf_router_context.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_session-safe.ecf b/library/server/obsolete/v0/wsf/wsf_session-safe.ecf index 0e713330..14608966 100644 --- a/library/server/obsolete/v0/wsf/wsf_session-safe.ecf +++ b/library/server/obsolete/v0/wsf/wsf_session-safe.ecf @@ -1,3 +1,3 @@ - + diff --git a/library/server/obsolete/v0/wsf/wsf_session.ecf b/library/server/obsolete/v0/wsf/wsf_session.ecf index a138e7a6..a64bd00b 100644 --- a/library/server/obsolete/v0/wsf/wsf_session.ecf +++ b/library/server/obsolete/v0/wsf/wsf_session.ecf @@ -1,3 +1,3 @@ - + diff --git a/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf index c347aae5..177c7b14 100644 --- a/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf +++ b/library/server/obsolete/v0/wsf_html/wsf_html-safe.ecf @@ -1,5 +1,5 @@ - + diff --git a/library/server/obsolete/v0/wsf_html/wsf_html.ecf b/library/server/obsolete/v0/wsf_html/wsf_html.ecf index 020415fa..ede0d213 100644 --- a/library/server/obsolete/v0/wsf_html/wsf_html.ecf +++ b/library/server/obsolete/v0/wsf_html/wsf_html.ecf @@ -1,5 +1,5 @@ - + @@ -9,13 +9,14 @@ - + + - - - - - + + + + + diff --git a/tools/estudio_wizard/lib/wizard/gui/graphical_wizard_application.e b/tools/estudio_wizard/lib/wizard/gui/graphical_wizard_application.e index c6117811..2c0478c2 100644 --- a/tools/estudio_wizard/lib/wizard/gui/graphical_wizard_application.e +++ b/tools/estudio_wizard/lib/wizard/gui/graphical_wizard_application.e @@ -38,7 +38,7 @@ feature {NONE} -- Initialization feature -- UI change - set_title (a_title: READABLE_STRING_GENERAL) + set_title (a_title: separate READABLE_STRING_GENERAL) deferred end From 1e10ce85183e0bbcb195297b89e4af3505f1ad86 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 31 Jul 2015 11:55:23 -0300 Subject: [PATCH 32/36] Updated set_value for WSF_FORM_SELECTABLE_INPUT (for example a checkbox). Call the feature set_checked_by_value iff the the current value exist in the list of values, in other case set checked in Flase. If we call set_checked_by_value without filter, previous checked values will be set in False. --- .../server/wsf_html/form/wsf_form_selectable_input.e | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/library/server/wsf_html/form/wsf_form_selectable_input.e b/library/server/wsf_html/form/wsf_form_selectable_input.e index 37c58366..7fff2b57 100644 --- a/library/server/wsf_html/form/wsf_form_selectable_input.e +++ b/library/server/wsf_html/form/wsf_form_selectable_input.e @@ -72,12 +72,22 @@ feature -- Change set_value (v: detachable WSF_VALUE) -- Set value `v' if applicable to Current + local + l_found: BOOLEAN do if attached {ITERABLE [WSF_VALUE]} v as lst then across lst as c + until + l_found loop - set_checked_by_value (c.item) + if attached {WSF_STRING} c.item as s and then is_same_value (s.value) then + set_checked_by_value (c.item) + l_found := true + end + end + if not l_found then + set_checked (False) end else set_checked_by_value (v) From 8651ff6e1e1030cc39379a09253478ba20735950 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 4 Aug 2015 13:03:51 +0200 Subject: [PATCH 33/36] Fixing `script_url' that wrongly used `path_info' instead of `percent_encoded_path_info'. (issue on script_url when path info contains unicode character). --- library/server/wsf/src/wsf_request.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e index 608b92cf..e644e70e 100644 --- a/library/server/wsf/src/wsf_request.e +++ b/library/server/wsf/src/wsf_request.e @@ -1902,7 +1902,7 @@ feature -- URL Utility elseif spos > 0 then i := spos end - spos := l_rq_uri.substring_index (path_info, i) + spos := l_rq_uri.substring_index (percent_encoded_path_info, i) if spos > 0 then l_base_url := l_rq_uri.substring (1, spos - 1) else From 47c5b798b38e2c9ac90fd2cee71b7e598ad24bf3 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 4 Aug 2015 13:24:03 +0200 Subject: [PATCH 34/36] Cosmetic true -> True --- library/server/wsf_html/form/wsf_form_selectable_input.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/server/wsf_html/form/wsf_form_selectable_input.e b/library/server/wsf_html/form/wsf_form_selectable_input.e index 7fff2b57..9c7b41ab 100644 --- a/library/server/wsf_html/form/wsf_form_selectable_input.e +++ b/library/server/wsf_html/form/wsf_form_selectable_input.e @@ -83,7 +83,7 @@ feature -- Change loop if attached {WSF_STRING} c.item as s and then is_same_value (s.value) then set_checked_by_value (c.item) - l_found := true + l_found := True end end if not l_found then From c824f707cfcaa710df6e12aea7b2ba413447cc49 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Wed, 5 Aug 2015 17:28:26 -0300 Subject: [PATCH 35/36] Fixed typo: Aug instead of Aou. --- library/network/protocol/http/src/http_date.e | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/network/protocol/http/src/http_date.e b/library/network/protocol/http/src/http_date.e index 70e489a4..454bc989 100644 --- a/library/network/protocol/http/src/http_date.e +++ b/library/network/protocol/http/src/http_date.e @@ -361,7 +361,7 @@ feature {NONE} -- Implementation when 5 then s.append ("May") when 6 then s.append ("Jun") when 7 then s.append ("Jul") - when 8 then s.append ("Aou") + when 8 then s.append ("Aug") when 9 then s.append ("Sep") when 10 then s.append ("Oct") when 11 then s.append ("Nov") @@ -487,7 +487,7 @@ feature {NONE} -- Implementation elseif l_mmm.same_string ("MAY") then l_mo := 05 elseif l_mmm.same_string ("JUN") then l_mo := 06 elseif l_mmm.same_string ("JUL") then l_mo := 07 - elseif l_mmm.same_string ("AOU") then l_mo := 08 + elseif l_mmm.same_string ("AUG") then l_mo := 08 elseif l_mmm.same_string ("SEP") then l_mo := 09 elseif l_mmm.same_string ("OCT") then l_mo := 10 elseif l_mmm.same_string ("NOV") then l_mo := 11 @@ -718,7 +718,7 @@ feature {NONE} -- Implementation elseif l_mmm.same_string ("MAY") then l_mo := 05 elseif l_mmm.same_string ("JUN") then l_mo := 06 elseif l_mmm.same_string ("JUL") then l_mo := 07 - elseif l_mmm.same_string ("AOU") then l_mo := 08 + elseif l_mmm.same_string ("AUG") then l_mo := 08 elseif l_mmm.same_string ("SEP") then l_mo := 09 elseif l_mmm.same_string ("OCT") then l_mo := 10 elseif l_mmm.same_string ("NOV") then l_mo := 11 @@ -905,7 +905,7 @@ feature {NONE} -- Implementation invariant note - copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software From 6c5159036906a23783ef84cfd4ec7f5ce0d203e7 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Mon, 24 Aug 2015 16:12:25 +0200 Subject: [PATCH 36/36] Updated installation location of openid and http_authorization in ISE package. Added iron package file for ewsgi. --- library/server/ewsgi/package.iron | 23 +++++++++++++++++++++++ tools/install_ewf.bat | 4 ++-- tools/uninstall_ewf.bat | 4 ++-- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 library/server/ewsgi/package.iron diff --git a/library/server/ewsgi/package.iron b/library/server/ewsgi/package.iron new file mode 100644 index 00000000..dac1a9b6 --- /dev/null +++ b/library/server/ewsgi/package.iron @@ -0,0 +1,23 @@ +package ewsgi + +project + ewsgi = "ewsgi-safe.ecf" + ewsgi = "ewsgi.ecf" + ewsgi_spec = "ewsgi_spec-safe.ecf" + ewsgi_spec = "ewsgi_spec.ecf" + connector_cgi = "connectors/cgi/cgi-safe.ecf" + connector_cgi = "connectors/cgi/cgi.ecf" + connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf" + connector_libfcgi = "connectors/libfcgi/libfcgi.ecf" + connector_nino = "connectors/nino/nino-safe.ecf" + connector_nino = "connectors/nino/nino.ecf" + connector_null = "connectors/null/null-safe.ecf" + connector_null = "connectors/null/null.ecf" + +note + title: EWSGI + description: EWSGI specification, and a few connectors. + tags: web, httpd, ewf + license: Eiffel Forum v2 + +end diff --git a/tools/install_ewf.bat b/tools/install_ewf.bat index 484db08d..8e26ee65 100644 --- a/tools/install_ewf.bat +++ b/tools/install_ewf.bat @@ -89,11 +89,11 @@ echo Install library: http echo Install library: content_negotiation %COPYCMD% %TMP_DIR%\library\network\protocol\content_negotiation %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation echo Install library: http_authorization -%SAFE_MD% %TMP_CONTRIB_DIR%\library\network\authentication +%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication %COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization echo Install library: openid -%SAFE_MD% %TMP_CONTRIB_DIR%\library\security +%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication %COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\web\authentication\openid echo Install library: uri_template diff --git a/tools/uninstall_ewf.bat b/tools/uninstall_ewf.bat index 6a3d2b86..39232ac2 100644 --- a/tools/uninstall_ewf.bat +++ b/tools/uninstall_ewf.bat @@ -60,9 +60,9 @@ echo Uninstall library: http echo Uninstall library: content_negotiation %RDCMD% %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation echo Uninstall library: http_authorization -%RDCMD% %TMP_CONTRIB_DIR%\library\network\authentication\http_authorization +%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization echo Uninstall library: security\openid -%RDCMD% %TMP_CONTRIB_DIR%\library\security\openid +%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\openid echo Uninstall library: uri_template %RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\uri_template echo Uninstall library: runtime\process\notification_email