From aec0136739f506bd24adff1c6f3e80e3c0c5de34 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 19 Oct 2011 00:34:30 +0200 Subject: [PATCH] First try to get a limited WGI_ and use WSF_ as default framework --- .../ewsgi/specification/request/wgi_request.e | 171 +- .../server/ewsgi/src/wgi_request_from_table.e | 867 +--------- library/server/request/rest/rest-safe.ecf | 7 +- library/server/request/rest/rest.ecf | 2 +- .../rest/src/contrib/doc/html/html_page.e | 4 +- .../src/contrib/doc/rest_api_documentation.e | 8 +- .../request/rest/src/response/rest_response.e | 4 +- .../rest/src/rest_request_agent_handler.e | 2 +- .../request/rest/src/rest_request_handler.e | 14 +- .../rest/src/uri/rest_request_uri_router.e | 2 +- .../uri/rest_request_uri_routing_handler_i.e | 6 +- .../rest_request_uri_template_router.e | 2 +- ...t_request_uri_template_routing_handler_i.e | 6 +- library/server/request/rest/tests/sample.ecf | 2 +- .../src/app/app_account_verify_credential.e | 10 +- .../request/rest/tests/src/app/app_test.e | 6 +- .../request/rest/tests/src/app_server.e | 12 +- .../gateway/cgi/rest_application_gateway.e | 2 +- .../gateway/fcgi/rest_application_gateway.e | 2 +- .../gateway/nino/rest_application_gateway.e | 2 +- .../tests/src/handler/app_request_handler.e | 2 +- .../tests/src/handler/app_request_helper.e | 2 +- library/server/request/router/router-safe.ecf | 4 +- library/server/request/router/router.ecf | 4 +- .../router/src/misc/request_format_utility.e | 2 +- .../misc/request_resource_handler_helper.e | 54 +- .../src/misc/routed_application_helper.e | 4 +- .../router/src/request_agent_handler.e | 4 +- .../router/src/request_file_system_handler.e | 22 +- .../request/router/src/request_handler.e | 6 +- .../router/src/request_handler_context.e | 19 +- .../request/router/src/request_router.e | 14 +- .../router/src/request_routing_handler.e | 6 +- .../request/router/src/routed_application_i.e | 6 +- .../src/uri/default/request_uri_router.e | 2 +- .../src/uri/request_uri_handler_context.e | 6 +- .../router/src/uri/request_uri_router_i.e | 8 +- .../default/request_uri_template_router.e | 2 +- .../request_uri_template_handler_context.e | 10 +- .../request_uri_template_router_i.e | 6 +- library/server/wsf/src/cgi_meta_names.e | 13 + .../request/value/wsf_multiple_string_value.e | 143 ++ .../wsf/src/request/value/wsf_string_value.e | 71 + library/server/wsf/src/request/wsf_value.e | 59 + library/server/wsf/src/support/wsf_error.e | 66 + library/server/wsf/src/support/wsf_header.e | 454 +++++ library/server/wsf/src/wsf_application.e | 32 + library/server/wsf/src/wsf_request.e | 1486 +++++++++++++++++ library/server/wsf/src/wsf_response.e | 164 ++ library/server/wsf/wsf-safe.ecf | 20 + library/server/wsf/wsf.ecf | 16 + 51 files changed, 2756 insertions(+), 1082 deletions(-) create mode 100644 library/server/wsf/src/cgi_meta_names.e create mode 100644 library/server/wsf/src/request/value/wsf_multiple_string_value.e create mode 100644 library/server/wsf/src/request/value/wsf_string_value.e create mode 100644 library/server/wsf/src/request/wsf_value.e create mode 100644 library/server/wsf/src/support/wsf_error.e create mode 100644 library/server/wsf/src/support/wsf_header.e create mode 100644 library/server/wsf/src/wsf_application.e create mode 100644 library/server/wsf/src/wsf_request.e create mode 100644 library/server/wsf/src/wsf_response.e create mode 100644 library/server/wsf/wsf-safe.ecf create mode 100644 library/server/wsf/wsf.ecf diff --git a/library/server/ewsgi/specification/request/wgi_request.e b/library/server/ewsgi/specification/request/wgi_request.e index 2e3c6a97..7f286400 100644 --- a/library/server/ewsgi/specification/request/wgi_request.e +++ b/library/server/ewsgi/specification/request/wgi_request.e @@ -80,23 +80,16 @@ feature -- Access: Input deferred end -feature -- Access: extra values - - request_time: detachable DATE_TIME - -- Request time (UTC) - deferred - end - feature -- Access: CGI meta variables - meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_STRING_VALUE + meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 -- Environment variable related to `a_name' require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + meta_string_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 -- Environment variable related to `a_name' require a_name_valid: a_name /= Void and then not a_name.is_empty @@ -106,7 +99,7 @@ feature -- Access: CGI meta variables end end - meta_variables: ITERABLE [WGI_STRING_VALUE] + meta_variables: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8] -- These variables are specific to requests made with HTTP. -- Interpretation of these variables may depend on the value of -- SERVER_PROTOCOL. @@ -138,7 +131,7 @@ feature -- Access: CGI meta variables feature -- Common Gateway Interface - 1.1 8 January 1996 - auth_type: detachable READABLE_STRING_32 + auth_type: detachable READABLE_STRING_8 -- This variable is specific to requests made via the "http" -- scheme. -- @@ -160,7 +153,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - content_length: detachable READABLE_STRING_32 + content_length: detachable READABLE_STRING_8 -- This metavariable is set to the size of the message-body -- entity attached to the request, if any, in decimal number of -- octets. If no data are attached, then this metavariable is @@ -180,7 +173,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - content_type: detachable READABLE_STRING_32 + content_type: detachable READABLE_STRING_8 -- If the request includes a message-body, CONTENT_TYPE is set to -- the Internet Media Type [9] of the attached entity if the type -- was provided via a "Content-type" field in the request header, @@ -223,7 +216,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - gateway_interface: READABLE_STRING_32 + gateway_interface: READABLE_STRING_8 -- This metavariable is set to the dialect of CGI being used by -- the server to communicate with the script. Syntax: -- @@ -256,7 +249,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - path_info: READABLE_STRING_32 + path_info: READABLE_STRING_8 -- The PATH_INFO metavariable specifies a path to be interpreted -- by the CGI script. It identifies the resource or sub-resource -- to be returned by the CGI script, and it is derived from the @@ -287,7 +280,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - path_translated: detachable READABLE_STRING_32 + path_translated: detachable READABLE_STRING_8 -- PATH_TRANSLATED is derived by taking any path-info component -- of the request URI (see section 6.1.6), decoding it (see -- section 3.1), parsing it as a URI in its own right, and @@ -333,7 +326,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - query_string: READABLE_STRING_32 + query_string: READABLE_STRING_8 -- A URL-encoded string; the part of the Script-URI. (See -- section 3.2.) -- @@ -350,7 +343,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - remote_addr: READABLE_STRING_32 + remote_addr: READABLE_STRING_8 -- The IP address of the client sending the request to the -- server. This is not necessarily that of the user agent (such -- as if the request came through a proxy). @@ -365,7 +358,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - remote_host: detachable READABLE_STRING_32 + remote_host: detachable READABLE_STRING_8 -- The fully qualified domain name of the client sending the -- request to the server, if available, otherwise NULL. (See -- section 6.1.9.) Fully qualified domain names take the form as @@ -376,7 +369,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - remote_ident: detachable READABLE_STRING_32 + remote_ident: detachable READABLE_STRING_8 -- The identity information reported about the connection by a -- RFC 1413 [11] request to the remote agent, if available. -- Servers MAY choose not to support this feature, or not to @@ -392,7 +385,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - remote_user: detachable READABLE_STRING_32 + remote_user: detachable READABLE_STRING_8 -- If the request required authentication using the "Basic" -- mechanism (i.e., the AUTH_TYPE metavariable is set to -- "Basic"), then the value of the REMOTE_USER metavariable is @@ -408,7 +401,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - request_method: READABLE_STRING_32 + request_method: READABLE_STRING_8 -- The REQUEST_METHOD metavariable is set to the method with -- which the request was made, as described in section 5.1.1 of -- the HTTP/1.0 specification [3] and section 5.1.1 of the @@ -429,7 +422,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - script_name: READABLE_STRING_32 + script_name: READABLE_STRING_8 -- The SCRIPT_NAME metavariable is set to a URL path that could -- identify the CGI script (rather than the script's output). The -- syntax and semantics are identical to a decoded HTTP URL @@ -447,7 +440,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - server_name: READABLE_STRING_32 + server_name: READABLE_STRING_8 -- The SERVER_NAME metavariable is set to the name of the server, -- as derived from the part of the Script-URI (see section -- 3.2). @@ -473,7 +466,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - server_protocol: READABLE_STRING_32 + server_protocol: READABLE_STRING_8 -- The SERVER_PROTOCOL metavariable is set to the name and -- revision of the information protocol with which the request -- arrived. This is not necessarily the same as the protocol @@ -501,7 +494,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - server_software: READABLE_STRING_32 + server_software: READABLE_STRING_8 -- The SERVER_SOFTWARE metavariable is set to the name and -- version of the information server software answering the -- request (and running the gateway). @@ -516,42 +509,42 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 feature -- HTTP_* - http_accept: detachable READABLE_STRING_32 + http_accept: detachable READABLE_STRING_8 -- Contents of the Accept: header from the current request, if there is one. -- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' deferred end - http_accept_charset: detachable READABLE_STRING_32 + http_accept_charset: detachable READABLE_STRING_8 -- Contents of the Accept-Charset: header from the current request, if there is one. -- Example: 'iso-8859-1,*,utf-8'. deferred end - http_accept_encoding: detachable READABLE_STRING_32 + http_accept_encoding: detachable READABLE_STRING_8 -- Contents of the Accept-Encoding: header from the current request, if there is one. -- Example: 'gzip'. deferred end - http_accept_language: detachable READABLE_STRING_32 + http_accept_language: detachable READABLE_STRING_8 -- Contents of the Accept-Language: header from the current request, if there is one. -- Example: 'en'. deferred end - http_connection: detachable READABLE_STRING_32 + http_connection: detachable READABLE_STRING_8 -- Contents of the Connection: header from the current request, if there is one. -- Example: 'Keep-Alive'. deferred end - http_host: detachable READABLE_STRING_32 + http_host: detachable READABLE_STRING_8 -- Contents of the Host: header from the current request, if there is one. deferred end - http_referer: detachable READABLE_STRING_32 + http_referer: detachable READABLE_STRING_8 -- The address of the page (if any) which referred the user agent to the current page. -- This is set by the user agent. -- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. @@ -559,7 +552,7 @@ feature -- HTTP_* deferred end - http_user_agent: detachable READABLE_STRING_32 + http_user_agent: detachable READABLE_STRING_8 -- Contents of the User-Agent: header from the current request, if there is one. -- This is a string denoting the user agent being which is accessing the page. -- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). @@ -568,127 +561,23 @@ feature -- HTTP_* deferred end - http_authorization: detachable READABLE_STRING_32 + http_authorization: detachable READABLE_STRING_8 -- Contents of the Authorization: header from the current request, if there is one. deferred end feature -- Extra CGI environment variables - request_uri: READABLE_STRING_32 + request_uri: READABLE_STRING_8 -- The URI which was given in order to access this page; for instance, '/index.html'. deferred end - orig_path_info: detachable READABLE_STRING_32 + orig_path_info: detachable READABLE_STRING_8 -- Original version of `path_info' before processed by Current environment deferred end -feature -- Query string Parameters - - query_parameters: ITERABLE [WGI_VALUE] - -- Variables extracted from QUERY_STRING - deferred - end - - query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Parameter for name `n'. - require - a_name_valid: a_name /= Void and then not a_name.is_empty - deferred - end - -feature -- Form fields and related - - form_data_parameters: ITERABLE [WGI_VALUE] - -- Variables sent by POST request - deferred - end - - form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Field for name `a_name'. - require - a_name_valid: a_name /= Void and then not a_name.is_empty - deferred - end - - uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, READABLE_STRING_GENERAL] - -- Table of uploaded files information - --| name: original path from the user - --| type: content type - --| tmp_name: path to temp file that resides on server - --| tmp_base_name: basename of `tmp_name' - --| error: if /= 0 , there was an error : TODO ... - --| size: size of the file given by the http request - deferred - end - -feature -- Cookies - - cookies: ITERABLE [WGI_VALUE] - -- Expanded cookies variable - deferred - end - - cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Field for name `a_name'. - require - a_name_valid: a_name /= Void and then not a_name.is_empty - deferred - end - -feature -- Access: all variables - - parameters: like items - obsolete "use items" - do - Result := items - end - - parameter (a_name: READABLE_STRING_GENERAL): like item - obsolete "use item" - do - Result := item (a_name) - end - - items: ITERABLE [WGI_VALUE] - -- Table containing all the various variables - -- Warning: this is computed each time, if you change the content of other containers - -- this won't update this Result's content, unless you query it again - deferred - end - - item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Variable named `a_name' from any of the variables container - -- and following a specific order - -- execution, environment, get, post, cookies - require - a_name_valid: a_name /= Void and then not a_name.is_empty - deferred - end - -feature -- Uploaded File Handling - - is_uploaded_file (a_filename: READABLE_STRING_GENERAL): BOOLEAN - -- Is `a_filename' a file uploaded via HTTP POST - deferred - end - -feature -- URL Utility - - absolute_script_url (a_path: STRING): STRING - -- Absolute Url for the script if any, extended by `a_path' - deferred - end - - script_url (a_path: STRING): STRING - -- Url relative to script name if any, extended by `a_path' - require - a_path_attached: a_path /= Void - deferred - end - invariant server_name_not_empty: not server_name.is_empty server_port_set: server_port /= 0 diff --git a/library/server/ewsgi/src/wgi_request_from_table.e b/library/server/ewsgi/src/wgi_request_from_table.e index 9d181d79..68055a2a 100644 --- a/library/server/ewsgi/src/wgi_request_from_table.e +++ b/library/server/ewsgi/src/wgi_request_from_table.e @@ -26,23 +26,20 @@ feature {NONE} -- Initialization create error_handler.make input := a_input set_meta_parameters (a_vars) - create uploaded_files.make (0) - - raw_post_data_recorded := True initialize analyze end - set_meta_parameters (a_vars: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_GENERAL]) + set_meta_parameters (a_vars: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]) -- Fill with variable from `a_vars' local s: like meta_string_variable - table: HASH_TABLE [WGI_STRING_VALUE, READABLE_STRING_GENERAL] + table: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8] l_query_string: like query_string l_request_uri: detachable STRING_32 do - create {STRING_32} empty_string.make_empty + create {STRING_8} empty_string.make_empty create table.make (a_vars.count) table.compare_objects @@ -122,19 +119,11 @@ feature {NONE} -- Initialization -- Specific initialization do --| Here one can set its own environment entries if needed - if meta_variable ({WGI_META_NAMES}.request_time) = Void then - set_meta_string_variable ({WGI_META_NAMES}.request_time, date_time_utilities.unix_time_stamp (Void).out) - end +-- if meta_variable ({WGI_META_NAMES}.request_time) = Void then +-- set_meta_string_variable ({WGI_META_NAMES}.request_time, date_time_utilities.unix_time_stamp (Void).out) +-- end end -feature -- Status - - raw_post_data_recorded: BOOLEAN assign set_raw_post_data_recorded - -- Record RAW POST DATA in meta parameters - -- otherwise just forget about it - -- Default: true - --| warning: you might keep in memory big amount of memory ... - feature -- Error handling has_error: BOOLEAN @@ -151,38 +140,38 @@ feature -- Access: Input input: WGI_INPUT_STREAM -- Server input channel -feature -- Access extra information - - request_time: detachable DATE_TIME - -- Request time (UTC) - do - if - attached {WGI_STRING_VALUE} meta_variable ({WGI_META_NAMES}.request_time) as t and then - t.string.is_integer_64 - then - Result := date_time_utilities.unix_time_stamp_to_date_time (t.string.to_integer_64) - end - end +--feature -- Access extra information +-- +-- request_time: detachable DATE_TIME +-- -- Request time (UTC) +-- do +-- if +-- attached {WGI_STRING_VALUE} meta_variable ({WGI_META_NAMES}.request_time) as t and then +-- t.string.is_integer_64 +-- then +-- Result := date_time_utilities.unix_time_stamp_to_date_time (t.string.to_integer_64) +-- end +-- end feature {NONE} -- Access: CGI meta parameters - meta_variables_table: HASH_TABLE [WGI_STRING_VALUE, READABLE_STRING_GENERAL] + meta_variables_table: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8] -- CGI Environment parameters feature -- Access: CGI meta parameters - meta_variables: ITERABLE [WGI_STRING_VALUE] + meta_variables: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8] do Result := meta_variables_table end - meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_STRING_VALUE + meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 -- CGI meta variable related to `a_name' do Result := meta_variables_table.item (a_name) end - meta_string_variable_or_default (a_name: READABLE_STRING_GENERAL; a_default: READABLE_STRING_32; use_default_when_empty: BOOLEAN): READABLE_STRING_32 + meta_string_variable_or_default (a_name: READABLE_STRING_8; a_default: READABLE_STRING_8; use_default_when_empty: BOOLEAN): READABLE_STRING_8 -- Value for meta parameter `a_name' -- If not found, return `a_default' require @@ -198,14 +187,14 @@ feature -- Access: CGI meta parameters end end - set_meta_string_variable (a_name: READABLE_STRING_GENERAL; a_value: READABLE_STRING_32) + set_meta_string_variable (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8) do meta_variables_table.force (new_string_value (a_name, a_value), a_name) ensure - param_set: attached {WGI_STRING_VALUE} meta_variable (a_name) as val and then val ~ a_value + param_set: attached meta_variable (a_name) as val and then val ~ a_value end - unset_meta_variable (a_name: READABLE_STRING_GENERAL) + unset_meta_variable (a_name: READABLE_STRING_8) do meta_variables_table.remove (a_name) ensure @@ -214,20 +203,20 @@ feature -- Access: CGI meta parameters feature -- Access: CGI meta parameters - 1.1 - auth_type: detachable READABLE_STRING_32 + auth_type: detachable READABLE_STRING_8 - content_length: detachable READABLE_STRING_32 + content_length: detachable READABLE_STRING_8 content_length_value: NATURAL_64 - content_type: detachable READABLE_STRING_32 + content_type: detachable READABLE_STRING_8 - gateway_interface: READABLE_STRING_32 + gateway_interface: READABLE_STRING_8 do Result := meta_string_variable_or_default ({WGI_META_NAMES}.gateway_interface, "", False) end - path_info: READABLE_STRING_32 + path_info: READABLE_STRING_8 -- -- --| For instance, if the current script was accessed via the URL @@ -235,88 +224,88 @@ feature -- Access: CGI meta parameters - 1.1 --| --| Note that is the PATH_INFO variable does not exists, the `path_info' value will be empty - path_translated: detachable READABLE_STRING_32 + path_translated: detachable READABLE_STRING_8 do Result := meta_string_variable ({WGI_META_NAMES}.path_translated) end - query_string: READABLE_STRING_32 + query_string: READABLE_STRING_8 - remote_addr: READABLE_STRING_32 + remote_addr: READABLE_STRING_8 - remote_host: READABLE_STRING_32 + remote_host: READABLE_STRING_8 - remote_ident: detachable READABLE_STRING_32 + remote_ident: detachable READABLE_STRING_8 do Result := meta_string_variable ({WGI_META_NAMES}.remote_ident) end - remote_user: detachable READABLE_STRING_32 + remote_user: detachable READABLE_STRING_8 do Result := meta_string_variable ({WGI_META_NAMES}.remote_user) end - request_method: READABLE_STRING_32 + request_method: READABLE_STRING_8 - script_name: READABLE_STRING_32 + script_name: READABLE_STRING_8 - server_name: READABLE_STRING_32 + server_name: READABLE_STRING_8 server_port: INTEGER - server_protocol: READABLE_STRING_32 + server_protocol: READABLE_STRING_8 do Result := meta_string_variable_or_default ({WGI_META_NAMES}.server_protocol, "HTTP/1.0", True) end - server_software: READABLE_STRING_32 + server_software: READABLE_STRING_8 do Result := meta_string_variable_or_default ({WGI_META_NAMES}.server_software, "Unknown Server", True) end feature -- Access: HTTP_* CGI meta parameters - 1.1 - http_accept: detachable READABLE_STRING_32 + http_accept: detachable READABLE_STRING_8 -- Contents of the Accept: header from the current request, if there is one. do Result := meta_string_variable ({WGI_META_NAMES}.http_accept) end - http_accept_charset: detachable READABLE_STRING_32 + http_accept_charset: detachable READABLE_STRING_8 -- Contents of the Accept-Charset: header from the current request, if there is one. -- Example: 'iso-8859-1,*,utf-8'. do Result := meta_string_variable ({WGI_META_NAMES}.http_accept_charset) end - http_accept_encoding: detachable READABLE_STRING_32 + http_accept_encoding: detachable READABLE_STRING_8 -- Contents of the Accept-Encoding: header from the current request, if there is one. -- Example: 'gzip'. do Result := meta_string_variable ({WGI_META_NAMES}.http_accept_encoding) end - http_accept_language: detachable READABLE_STRING_32 + http_accept_language: detachable READABLE_STRING_8 -- Contents of the Accept-Language: header from the current request, if there is one. -- Example: 'en'. do Result := meta_string_variable ({WGI_META_NAMES}.http_accept_language) end - http_connection: detachable READABLE_STRING_32 + http_connection: detachable READABLE_STRING_8 -- Contents of the Connection: header from the current request, if there is one. -- Example: 'Keep-Alive'. do Result := meta_string_variable ({WGI_META_NAMES}.http_connection) end - http_host: detachable READABLE_STRING_32 + http_host: detachable READABLE_STRING_8 -- Contents of the Host: header from the current request, if there is one. do Result := meta_string_variable ({WGI_META_NAMES}.http_host) end - http_referer: detachable READABLE_STRING_32 + http_referer: detachable READABLE_STRING_8 -- The address of the page (if any) which referred the user agent to the current page. -- This is set by the user agent. -- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. @@ -325,7 +314,7 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1 Result := meta_string_variable ({WGI_META_NAMES}.http_referer) end - http_user_agent: detachable READABLE_STRING_32 + http_user_agent: detachable READABLE_STRING_8 -- Contents of the User-Agent: header from the current request, if there is one. -- This is a string denoting the user agent being which is accessing the page. -- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). @@ -335,7 +324,7 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1 Result := meta_string_variable ({WGI_META_NAMES}.http_user_agent) end - http_authorization: detachable READABLE_STRING_32 + http_authorization: detachable READABLE_STRING_8 -- Contents of the Authorization: header from the current request, if there is one. do Result := meta_string_variable ({WGI_META_NAMES}.http_authorization) @@ -343,15 +332,15 @@ feature -- Access: HTTP_* CGI meta parameters - 1.1 feature -- Access: Extension to CGI meta parameters - 1.1 - request_uri: READABLE_STRING_32 + request_uri: READABLE_STRING_8 -- The URI which was given in order to access this page; for instance, '/index.html'. - orig_path_info: detachable READABLE_STRING_32 + orig_path_info: detachable READABLE_STRING_8 -- Original version of `path_info' before processed by Current environment feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO - set_orig_path_info (s: READABLE_STRING_32) + set_orig_path_info (s: READABLE_STRING_8) -- Set ORIG_PATH_INFO to `s' require s_attached: s /= Void @@ -392,739 +381,14 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO end end -feature {NONE} -- Query parameters - - query_parameters_table: HASH_TABLE [WGI_VALUE, READABLE_STRING_GENERAL] - -- Variables extracted from QUERY_STRING - local - vars: like internal_query_parameters_table - p,e: INTEGER - rq_uri: like request_uri - s: detachable STRING - do - vars := internal_query_parameters_table - if vars = Void then - s := query_string - if s = Void then - rq_uri := request_uri - p := rq_uri.index_of ('?', 1) - if p > 0 then - e := rq_uri.index_of ('#', p + 1) - if e = 0 then - e := rq_uri.count - else - e := e - 1 - end - s := rq_uri.substring (p+1, e) - end - end - vars := urlencoded_parameters (s, True) - vars.compare_objects - internal_query_parameters_table := vars - end - Result := vars - end - -feature -- Query parameters - - query_parameters: ITERABLE [WGI_VALUE] - do - Result := query_parameters_table - end - - query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Parameter for name `n'. - do - Result := query_parameters_table.item (a_name) - end - -feature {NONE} -- Query parameters: implementation - - urlencoded_parameters (a_content: detachable READABLE_STRING_8; decoding: BOOLEAN): HASH_TABLE [WGI_VALUE, STRING] - -- Import `a_content' - local - n, p, i, j: INTEGER - s: STRING - l_name,l_value: STRING_32 - v: WGI_VALUE - do - if a_content = Void then - create Result.make (0) - else - n := a_content.count - if n = 0 then - create Result.make (0) - else - create Result.make (3) - from - p := 1 - until - p = 0 - loop - i := a_content.index_of ('&', p) - if i = 0 then - s := a_content.substring (p, n) - p := 0 - else - s := a_content.substring (p, i - 1) - p := i + 1 - end - if not s.is_empty then - j := s.index_of ('=', 1) - if j > 0 then - l_name := s.substring (1, j - 1) - l_value := s.substring (j + 1, s.count) - if decoding then - l_name := url_encoder.decoded_string (l_name) - l_value := url_encoder.decoded_string (l_value) - end - v := new_string_value (l_name, l_value) - if Result.has_key (l_name) and then attached Result.found_item as l_existing_value then - if attached {WGI_MULTIPLE_STRING_VALUE} l_existing_value as l_multi then - l_multi.add_value (v) - else - Result.force (create {WGI_MULTIPLE_STRING_VALUE}.make_with_array (<>), l_name) - check replaced: Result.found and then Result.found_item ~ l_existing_value end - end - else - Result.force (v, l_name) - end - end - end - end - end - end - end - -feature {NONE} -- Form fields and related - - form_data_parameters_table: HASH_TABLE [WGI_VALUE, READABLE_STRING_GENERAL] - -- Variables sent by POST request - local - vars: like internal_form_data_parameters_table - s: STRING - n: NATURAL_64 - l_type: like content_type - do - vars := internal_form_data_parameters_table - if vars = Void then - n := content_length_value - if n > 0 then - l_type := content_type - if - l_type /= Void and then - l_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data) - then - create vars.make (5) - vars.compare_objects - --| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ... - s := form_input_data (n.to_integer_32) --| FIXME truncated from NAT64 to INT32 - analyze_multipart_form (l_type, s, vars) - else - s := form_input_data (n.to_integer_32) --| FIXME truncated from NAT64 to INT32 - vars := urlencoded_parameters (s, True) - end - if raw_post_data_recorded then - set_meta_string_variable ("RAW_POST_DATA", s) - end - else - create vars.make (0) - vars.compare_objects - end - internal_form_data_parameters_table := vars - end - Result := vars - end - -feature -- Form fields and related - - form_data_parameters: ITERABLE [WGI_VALUE] - do - Result := form_data_parameters_table - end - - form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Field for name `a_name'. - do - Result := form_data_parameters_table.item (a_name) - end - - uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, STRING] - -- Table of uploaded files information - --| name: original path from the user - --| type: content type - --| tmp_name: path to temp file that resides on server - --| tmp_base_name: basename of `tmp_name' - --| error: if /= 0 , there was an error : TODO ... - --| size: size of the file given by the http request - -feature {NONE} -- Cookies - - cookies_table: HASH_TABLE [WGI_VALUE, READABLE_STRING_GENERAL] - -- Expanded cookies variable - local - i,j,p,n: INTEGER - l_cookies: like internal_cookies_table - k,v,s: STRING - do - l_cookies := internal_cookies_table - if l_cookies = Void then - if attached {WGI_STRING_VALUE} meta_variable ({WGI_META_NAMES}.http_cookie) as val then - s := val.string - create l_cookies.make (5) - l_cookies.compare_objects - from - n := s.count - p := 1 - i := 1 - until - p < 1 - loop - i := s.index_of ('=', p) - if i > 0 then - j := s.index_of (';', i) - if j = 0 then - j := n + 1 - k := s.substring (p, i - 1) - v := s.substring (i + 1, n) - - p := 0 -- force termination - else - k := s.substring (p, i - 1) - v := s.substring (i + 1, j - 1) - p := j + 1 - end - l_cookies.force (new_string_value (k, v), k) - end - end - else - create l_cookies.make (0) - l_cookies.compare_objects - end - internal_cookies_table := l_cookies - end - Result := l_cookies - end - -feature -- Cookies - - cookies: ITERABLE [WGI_VALUE] - do - Result := cookies_table - end - - cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Field for name `a_name'. - do - Result := cookies_table.item (a_name) - end - -feature {NONE} -- Access: global variable - - items_table: HASH_TABLE [WGI_VALUE, READABLE_STRING_GENERAL] - -- Table containing all the various variables - -- Warning: this is computed each time, if you change the content of other containers - -- this won't update this Result's content, unless you query it again - do - create Result.make (100) - - across - meta_variables as vars - loop - Result.force (vars.item, vars.item.name) - end - - across - query_parameters as vars - loop - Result.force (vars.item, vars.item.name) - end - - across - form_data_parameters as vars - loop - Result.force (vars.item, vars.item.name) - end - - across - cookies as vars - loop - Result.force (vars.item, vars.item.name) - end - - end - -feature -- Access: global variable - - items: ITERABLE [WGI_VALUE] - do - Result := items_table - end - - item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE - -- Variable named `a_name' from any of the variables container - -- and following a specific order - -- execution, environment, get, post, cookies - local - v: detachable WGI_VALUE - do - v := meta_variable (a_name) - if v = Void then - v := query_parameter (a_name) - if v = Void then - v := form_data_parameter (a_name) - if v = Void then - v := cookie (a_name) - end - end - end --- if s /= Void then --- Result := s.as_string_32 --- end - end - - string_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 - do - if attached {WGI_STRING_VALUE} item (a_name) as val then - Result := val.string - else - check is_string_value: False end - end - end - -feature -- Uploaded File Handling - - is_uploaded_file (a_filename: STRING): BOOLEAN - -- Is `a_filename' a file uploaded via HTTP Form - local - l_files: like uploaded_files - do - l_files := uploaded_files - if not l_files.is_empty then - from - l_files.start - until - l_files.after or Result - loop - if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string (a_filename) then - Result := True - end - l_files.forth - end - end - end - -feature -- URL Utility - - absolute_script_url (a_path: STRING): STRING - -- Absolute Url for the script if any, extended by `a_path' - do - Result := script_url (a_path) - if attached http_host as h then - Result.prepend (h) - Result.prepend ("http://") - else - --| Issue ?? - end - end - - script_url (a_path: STRING): STRING - -- Url relative to script name if any, extended by `a_path' - local - l_base_url: like internal_url_base - i,m,n: INTEGER - l_rq_uri: like request_uri - do - l_base_url := internal_url_base - if l_base_url = Void then - if attached script_name as l_script_name then - l_rq_uri := request_uri - if l_rq_uri.starts_with (l_script_name) then - l_base_url := l_script_name - else - --| Handle Rewrite url engine, to have clean path - from - i := 1 - m := l_rq_uri.count - n := l_script_name.count - until - i > m or i > n or l_rq_uri[i] /= l_script_name[i] - loop - i := i + 1 - end - if i > 1 then - if l_rq_uri[i-1] = '/' then - i := i -1 - end - l_base_url := l_rq_uri.substring (1, i - 1) - end - end - end - if l_base_url = Void then - create l_base_url.make_empty - end - internal_url_base := l_base_url - end - Result := l_base_url + a_path - end - -feature {NONE} -- Implementation: URL Utility - - internal_url_base: detachable STRING - -- URL base of potential script - feature -- Element change - set_raw_post_data_recorded (b: BOOLEAN) - -- Set `raw_post_data_recorded' to `b' - do - raw_post_data_recorded := b - end - set_error_handler (ehdl: like error_handler) -- Set `error_handler' to `ehdl' do error_handler := ehdl end -feature {NONE} -- Temporary File handling - - delete_uploaded_file (uf: WGI_UPLOADED_FILE_DATA) - -- Delete file `a_filename' - require - uf_valid: uf /= Void - local - f: RAW_FILE - do - if uploaded_files.has_item (uf) then - if attached uf.tmp_name as fn then - create f.make (fn) - if f.exists and then f.is_writable then - f.delete - else - error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete file %""+ fn +"%"") - end - else - error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete uploaded file %""+ uf.name +"%" Tmp File not found") - end - else - error_handler.add_custom_error (0, "Not an uploaded file", "This file %""+ uf.name +"%" is not an uploaded file.") - end - end - - save_uploaded_file (a_content: STRING; a_up_fn_info: WGI_UPLOADED_FILE_DATA) - -- Save uploaded file content to `a_filename' - local - bn: STRING - l_safe_name: STRING - f: RAW_FILE - dn: STRING - fn: FILE_NAME - d: DIRECTORY - n: INTEGER - rescued: BOOLEAN - do - if not rescued then - dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory - create d.make (dn) - if d.exists and then d.is_writable then - l_safe_name := safe_filename (a_up_fn_info.name) - from - create fn.make_from_string (dn) - bn := "tmp-" + l_safe_name - fn.set_file_name (bn) - create f.make (fn.string) - n := 0 - until - not f.exists - or else n > 1_000 - loop - n := n + 1 - fn.make_from_string (dn) - bn := "tmp-" + n.out + "-" + l_safe_name - fn.set_file_name (bn) - f.make (fn.string) - end - - if not f.exists or else f.is_writable then - a_up_fn_info.set_tmp_name (f.name) - a_up_fn_info.set_tmp_basename (bn) - f.open_write - f.put_string (a_content) - f.close - else - a_up_fn_info.set_error (-1) - end - else - error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"") - end - else - a_up_fn_info.set_error (-1) - end - rescue - rescued := True - retry - end - - safe_filename (fn: STRING): STRING - local - c: CHARACTER - i, n, p: INTEGER - l_accentued, l_non_accentued: STRING - do - l_accentued := "ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ" - l_non_accentued := "AAAAAACEEEEIIIIOOOOOUUUUYaaaaaaceeeeiiiioooooouuuuyy" - - --| Compute safe filename, to avoid creating impossible filename, or dangerous one - from - i := 1 - n := fn.count - create Result.make (n) - until - i > n - loop - c := fn[i] - inspect c - when '.', '-', '_' then - Result.extend (c) - when 'A' .. 'Z', 'a' .. 'z', '0' .. '9' then - Result.extend (c) - else - p := l_accentued.index_of (c, 1) - if p > 0 then - Result.extend (l_non_accentued[p]) - else - Result.extend ('-') - end - end - i := i + 1 - end - end - -feature {NONE} -- Implementation: Form analyzer - - analyze_multipart_form (t: STRING; s: STRING; vars: like form_data_parameters_table) - -- Analyze multipart form content - --| FIXME[2011-06-21]: integrate eMIME parser library - require - t_attached: t /= Void - s_attached: s /= Void - vars_attached: vars /= Void - local - p,i,next_b: INTEGER - l_boundary_prefix: STRING - l_boundary: STRING - l_boundary_len: INTEGER - m: STRING - is_crlf: BOOLEAN - do - p := t.substring_index ("boundary=", 1) - if p > 0 then - l_boundary := t.substring (p + 9, t.count) - p := s.substring_index (l_boundary, 1) - if p > 1 then - l_boundary_prefix := s.substring (1, p - 1) - l_boundary := l_boundary_prefix + l_boundary - else - create l_boundary_prefix.make_empty - end - l_boundary_len := l_boundary.count - --| Let's support either %R%N and %N ... - --| Since both cases might occurs (for instance, our implementation of CGI does not have %R%N) - --| then let's be as flexible as possible on this. - is_crlf := s[l_boundary_len + 1] = '%R' - from - i := 1 + l_boundary_len + 1 - if is_crlf then - i := i + 1 --| +1 = CR = %R - end - next_b := i - until - i = 0 - loop - next_b := s.substring_index (l_boundary, i) - if next_b > 0 then - if is_crlf then - m := s.substring (i, next_b - 1 - 2) --| 2 = CR LF = %R %N - else - m := s.substring (i, next_b - 1 - 1) --| 1 = LF = %N - end - analyze_multipart_form_input (m, vars) - i := next_b + l_boundary_len + 1 - if is_crlf then - i := i + 1 --| +1 = CR = %R - end - else - if is_crlf then - i := i + 1 - end - m := s.substring (i - 1, s.count) - m.right_adjust - if not l_boundary_prefix.same_string (m) then - error_handler.add_custom_error (0, "Invalid form data", "Invalid ending for form data from input") - end - i := next_b - end - end - end - end - - analyze_multipart_form_input (s: STRING; vars_post: like form_data_parameters_table) - -- Analyze multipart entry - require - s_not_empty: s /= Void and then not s.is_empty - local - n, i,p, b,e: INTEGER - l_name, l_filename, l_content_type: detachable STRING - l_header: detachable STRING - l_content: detachable STRING - l_line: detachable STRING - l_up_file_info: WGI_UPLOADED_FILE_DATA - do - from - p := 1 - n := s.count - until - p > n or l_header /= Void - loop - inspect s[p] - when '%R' then -- CR - if - n >= p + 3 and then - s[p+1] = '%N' and then -- LF - s[p+2] = '%R' and then -- CR - s[p+3] = '%N' -- LF - then - l_header := s.substring (1, p + 1) - l_content := s.substring (p + 4, n) - end - when '%N' then - if - n >= p + 1 and then - s[p+1] = '%N' - then - l_header := s.substring (1, p) - l_content := s.substring (p + 2, n) - end - else - end - p := p + 1 - end - if l_header /= Void and l_content /= Void then - from - i := 1 - n := l_header.count - until - i = 0 or i > n - loop - l_line := Void - b := i - p := l_header.index_of ('%N', b) - if p > 0 then - if l_header[p - 1] = '%R' then - p := p - 1 - i := p + 2 - else - i := p + 1 - end - end - if p > 0 then - l_line := l_header.substring (b, p - 1) - if l_line.starts_with ("Content-Disposition: form-data") then - p := l_line.substring_index ("name=", 1) - if p > 0 then - p := p + 4 --| 4 = ("name=").count - 1 - if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then - p := p + 1 - e := l_line.index_of ('"', p + 1) - else - e := l_line.index_of (';', p + 1) - if e = 0 then - e := l_line.count - end - end - l_name := l_header.substring (p + 1, e - 1) - end - - p := l_line.substring_index ("filename=", 1) - if p > 0 then - p := p + 8 --| 8 = ("filename=").count - 1 - if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then - p := p + 1 - e := l_line.index_of ('"', p + 1) - else - e := l_line.index_of (';', p + 1) - if e = 0 then - e := l_line.count - end - end - l_filename := l_header.substring (p + 1, e - 1) - end - elseif l_line.starts_with ("Content-Type: ") then - l_content_type := l_line.substring (15, l_line.count) - end - else - i := 0 - end - end - if l_name /= Void then - if l_filename /= Void then - if l_content_type = Void then - l_content_type := default_content_type - end - create l_up_file_info.make (l_filename, l_content_type, l_content.count) - save_uploaded_file (l_content, l_up_file_info) - uploaded_files.force (l_up_file_info, l_name) - else - vars_post.force (new_string_value (l_name, l_content), l_name) - end - else - error_handler.add_custom_error (0, "unamed multipart entry", Void) - end - else - error_handler.add_custom_error (0, "missformed multipart entry", Void) - end - end - -feature {NONE} -- Internal value - - default_content_type: STRING = "text/plain" - -- Default content type - - form_input_data (nb: INTEGER): STRING - -- data from input form - local - n: INTEGER - t: STRING - do - from - n := nb - create Result.make (n) - if n > 1_024 then - n := 1_024 - end - until - n <= 0 - loop - read_input (n) - t := last_input_string - Result.append_string (t) - if t.count < n then - n := 0 - end - n := nb - t.count - end - end - - internal_query_parameters_table: detachable like query_parameters_table - -- cached value for `query_parameters' - - internal_form_data_parameters_table: detachable like form_data_parameters_table - -- cached value for `form_fields' - - internal_cookies_table: detachable like cookies_table - -- cached value for `cookies' - feature {NONE} -- I/O: implementation read_input (nb: INTEGER) @@ -1156,7 +420,7 @@ feature {NONE} -- Implementation analyze -- Extract relevant meta parameters local - s: detachable READABLE_STRING_32 + s: detachable READABLE_STRING_8 do s := request_uri if s.is_empty then @@ -1181,7 +445,7 @@ feature {NONE} -- Implementation feature {NONE} -- Implementation: utilities - single_slash_starting_string (s: READABLE_STRING_32): STRING_32 + single_slash_starting_string (s: READABLE_STRING_8): STRING_8 -- Return the string `s' (or twin) with one and only one starting slash local i, n: INTEGER @@ -1227,24 +491,19 @@ feature {NONE} -- Implementation: utilities one_starting_slash: Result[1] = '/' and (Result.count = 1 or else Result[2] /= '/') end - new_string_value (a_name: READABLE_STRING_GENERAL; a_value: READABLE_STRING_32): WGI_STRING_VALUE + new_string_value (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8): READABLE_STRING_8 do - create Result.make (a_name, a_value) + Result := a_value end - empty_string: READABLE_STRING_32 + empty_string: READABLE_STRING_8 -- Reusable empty string - url_encoder: URL_ENCODER - once - create Result - end - - date_time_utilities: HTTP_DATE_TIME_UTILITIES - -- Utilities classes related to date and time. - once - create Result - end +-- date_time_utilities: HTTP_DATE_TIME_UTILITIES +-- -- Utilities classes related to date and time. +-- once +-- create Result +-- end invariant empty_string_unchanged: empty_string.is_empty diff --git a/library/server/request/rest/rest-safe.ecf b/library/server/request/rest/rest-safe.ecf index a6865a9a..ad2cfd15 100644 --- a/library/server/request/rest/rest-safe.ecf +++ b/library/server/request/rest/rest-safe.ecf @@ -7,12 +7,13 @@ /\.git$ /\.svn$ - - + - + /html$ diff --git a/library/server/request/rest/rest.ecf b/library/server/request/rest/rest.ecf index 0c5c4034..502bf28f 100644 --- a/library/server/request/rest/rest.ecf +++ b/library/server/request/rest/rest.ecf @@ -9,7 +9,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/library/server/request/router/router.ecf b/library/server/request/router/router.ecf index 93fae79f..664d0879 100644 --- a/library/server/request/router/router.ecf +++ b/library/server/request/router/router.ecf @@ -12,7 +12,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/library/server/request/router/src/misc/request_format_utility.e b/library/server/request/router/src/misc/request_format_utility.e index 12556be7..ca0dd7ab 100644 --- a/library/server/request/router/src/misc/request_format_utility.e +++ b/library/server/request/router/src/misc/request_format_utility.e @@ -9,7 +9,7 @@ class feature -- Access - accepted_content_types (req: WGI_REQUEST): detachable ARRAYED_LIST [READABLE_STRING_8] + accepted_content_types (req: WSF_REQUEST): detachable ARRAYED_LIST [READABLE_STRING_8] local s: STRING_8 q: READABLE_STRING_8 diff --git a/library/server/request/router/src/misc/request_resource_handler_helper.e b/library/server/request/router/src/misc/request_resource_handler_helper.e index f106b16f..51b24faf 100644 --- a/library/server/request/router/src/misc/request_resource_handler_helper.e +++ b/library/server/request/router/src/misc/request_resource_handler_helper.e @@ -9,7 +9,7 @@ class feature -- Execute template - execute_methods (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_methods (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request and dispatch according to the request method local m: READABLE_STRING_8 @@ -41,7 +41,7 @@ feature -- Execute template feature -- Method Post - execute_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_post (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do if req.content_length_value > 0 then do_post (ctx, req, res) @@ -50,14 +50,14 @@ feature -- Method Post end end - do_post (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_post (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method POST not implemented", ctx, req, res) end feature-- Method Put - execute_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_put (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do if req.content_length_value > 0 then do_put (ctx, req, res) @@ -66,91 +66,91 @@ feature-- Method Put end end - do_put (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_put (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method PUT not implemented", ctx, req, res) end feature -- Method Get - execute_get (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_get (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_get (ctx, req, res) end - do_get (ctx: C;req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_get (ctx: C;req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method HEAD not implemented", ctx, req, res) end feature -- Method DELETE - execute_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_delete (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_delete (ctx, req, res) end - do_delete (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_delete (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method DELETE not implemented", ctx, req, res) end feature -- Method CONNECT - execute_connect (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_connect (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_connect (ctx, req, res) end - do_connect (ctx: C;req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_connect (ctx: C;req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method CONNECT not implemented", ctx, req, res) end feature -- Method HEAD - execute_head (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_head (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_head (ctx, req, res) end - do_head (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_head (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method HEAD not implemented", ctx, req, res) end feature -- Method OPTIONS - execute_options (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_options (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_options (ctx, req, res) end - do_options (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_options (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method OPTIONS not implemented", ctx, req, res) end feature -- Method TRACE - execute_trace (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_trace (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_trace (ctx, req, res) end - do_trace (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_trace (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method TRACE not implemented", ctx, req, res) end feature -- Method Extension Method - execute_extension_method (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_extension_method (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do do_extension_method (ctx, req, res) end - do_extension_method (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do_extension_method (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do handle_not_implemented ("Method extension-method not implemented", ctx, req, res) end @@ -164,9 +164,9 @@ feature -- Handle responses Result := Void end - handle_bad_request_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) + handle_bad_request_response (a_description:STRING; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE ) local - h : EWF_HEADER + h : WSF_HEADER do create h.make h.put_status ({HTTP_STATUS_CODE}.bad_request) @@ -182,9 +182,9 @@ feature -- Handle responses res.write_string (a_description) end - handle_internal_server_error (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) + handle_internal_server_error (a_description:STRING; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE ) local - h : EWF_HEADER + h : WSF_HEADER do create h.make h.put_status ({HTTP_STATUS_CODE}.internal_server_error) @@ -202,9 +202,9 @@ feature -- Handle responses res.write_string (a_description) end - handle_not_implemented (a_description: STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER ) + handle_not_implemented (a_description: STRING; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE ) local - h : EWF_HEADER + h : WSF_HEADER do create h.make h.put_status ({HTTP_STATUS_CODE}.not_implemented) @@ -220,9 +220,9 @@ feature -- Handle responses res.write_string (a_description) end - handle_resource_not_found_response (a_description:STRING; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + handle_resource_not_found_response (a_description:STRING; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local - h : EWF_HEADER + h : WSF_HEADER do create h.make h.put_status ({HTTP_STATUS_CODE}.not_found) diff --git a/library/server/request/router/src/misc/routed_application_helper.e b/library/server/request/router/src/misc/routed_application_helper.e index ce36ac54..681c3f5d 100644 --- a/library/server/request/router/src/misc/routed_application_helper.e +++ b/library/server/request/router/src/misc/routed_application_helper.e @@ -12,7 +12,7 @@ inherit feature -- Helper - execute_content_type_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING]) + execute_content_type_not_allowed (req: WSF_REQUEST; res: WSF_RESPONSE; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING]) local accept_s, uri_s: detachable STRING i, n: INTEGER @@ -62,7 +62,7 @@ feature -- Helper end end - execute_request_method_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_methods: ITERABLE [STRING]) + execute_request_method_not_allowed (req: WSF_REQUEST; res: WSF_RESPONSE; a_methods: ITERABLE [STRING]) local s: STRING do diff --git a/library/server/request/router/src/request_agent_handler.e b/library/server/request/router/src/request_agent_handler.e index 66704ece..87365d7e 100644 --- a/library/server/request/router/src/request_agent_handler.e +++ b/library/server/request/router/src/request_agent_handler.e @@ -22,11 +22,11 @@ feature -- Initialization feature -- Access - action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]] + action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]] feature -- Execution - execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) do action.call ([ctx, req, res]) end diff --git a/library/server/request/router/src/request_file_system_handler.e b/library/server/request/router/src/request_file_system_handler.e index 5c398244..86865253 100644 --- a/library/server/request/router/src/request_file_system_handler.e +++ b/library/server/request/router/src/request_file_system_handler.e @@ -45,10 +45,10 @@ feature -- Element change feature -- Execution - execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request handler local - h: EWF_HEADER + h: WSF_HEADER s: STRING uri: STRING do @@ -68,7 +68,7 @@ feature -- Execution end end - process_uri (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + process_uri (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local f: RAW_FILE fn: READABLE_STRING_8 @@ -90,9 +90,9 @@ feature -- Execution end end - respond_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + respond_index (a_uri: READABLE_STRING_8; dn: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local - h: EWF_HEADER + h: WSF_HEADER uri, s: STRING_8 d: DIRECTORY l_files: LIST [STRING_8] @@ -145,10 +145,10 @@ feature -- Execution d.close end - respond_file (f: FILE; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + respond_file (f: FILE; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local fn: READABLE_STRING_8 - h: EWF_HEADER + h: WSF_HEADER ext: READABLE_STRING_8 ct: detachable READABLE_STRING_8 do @@ -175,9 +175,9 @@ feature -- Execution res.flush end - respond_not_found (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + respond_not_found (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local - h: EWF_HEADER + h: WSF_HEADER s: STRING_8 do create h.make @@ -191,9 +191,9 @@ feature -- Execution res.flush end - respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + respond_access_denied (uri: READABLE_STRING_8; ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) local - h: EWF_HEADER + h: WSF_HEADER s: STRING_8 do create h.make diff --git a/library/server/request/router/src/request_handler.e b/library/server/request/router/src/request_handler.e index 76ba939b..71822760 100644 --- a/library/server/request/router/src/request_handler.e +++ b/library/server/request/router/src/request_handler.e @@ -17,7 +17,7 @@ inherit feature -- Status report - is_valid_context (req: WGI_REQUEST): BOOLEAN + is_valid_context (req: WSF_REQUEST): BOOLEAN -- Is `req' valid context for current handler? do Result := True @@ -25,7 +25,7 @@ feature -- Status report feature -- Execution - execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request handler require is_valid_context: is_valid_context (req) @@ -34,7 +34,7 @@ feature -- Execution feature -- Execution: report - url (req: WGI_REQUEST; a_base: detachable READABLE_STRING_8; args: detachable STRING; abs: BOOLEAN): STRING + url (req: WSF_REQUEST; a_base: detachable READABLE_STRING_8; args: detachable STRING; abs: BOOLEAN): STRING -- Associated url based on `a_base' and `args' -- if `abs' then return absolute url local diff --git a/library/server/request/router/src/request_handler_context.e b/library/server/request/router/src/request_handler_context.e index 0e29c643..db2e908e 100644 --- a/library/server/request/router/src/request_handler_context.e +++ b/library/server/request/router/src/request_handler_context.e @@ -16,7 +16,7 @@ inherit feature -- Access - request: WGI_REQUEST + request: WSF_REQUEST -- Associated request path: READABLE_STRING_8 @@ -71,12 +71,11 @@ feature -- Query request_content_type (content_type_supported: detachable ARRAY [READABLE_STRING_8]): detachable READABLE_STRING_8 local - s: detachable READABLE_STRING_32 + s: detachable READABLE_STRING_8 i,n: INTEGER do - s := request.content_type - if s /= Void then - Result := s + if attached request.content_type as ct then + Result := ct else if attached accepted_content_types (request) as l_accept_lst then from @@ -108,18 +107,18 @@ feature -- Query feature -- Query - path_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + path_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE -- Parameter value for path variable `a_name' deferred end - query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE -- Parameter value for query variable `a_name' --| i.e after the ? character deferred end - parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE -- Any parameter value for variable `a_name' -- URI template parameter and query parameters do @@ -131,9 +130,9 @@ feature -- Query feature -- String query - string_from (a_value: detachable WGI_VALUE): detachable READABLE_STRING_32 + string_from (a_value: detachable WSF_VALUE): detachable READABLE_STRING_32 do - if attached {WGI_STRING_VALUE} a_value as val then + if attached {WSF_STRING_VALUE} a_value as val then Result := val.string end end diff --git a/library/server/request/router/src/request_router.e b/library/server/request/router/src/request_router.e index 901b3e83..e903a893 100644 --- a/library/server/request/router/src/request_router.e +++ b/library/server/request/router/src/request_router.e @@ -34,12 +34,12 @@ feature -- Mapping deferred end - map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) + map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) do map_agent_with_request_methods (a_resource, a_action, Void) end - map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) local rah: REQUEST_AGENT_HANDLER [C] @@ -65,14 +65,14 @@ feature -- Base url feature -- Execution - dispatch (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): BOOLEAN + dispatch (req: WSF_REQUEST; res: WSF_RESPONSE): BOOLEAN -- Dispatch `req, res' to the associated handler -- And return True is handled, otherwise False do Result := dispatch_and_return_handler (req, res) /= Void end - dispatch_and_return_handler (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER): detachable H + dispatch_and_return_handler (req: WSF_REQUEST; res: WSF_RESPONSE): detachable H -- Dispatch `req, res' to the associated handler -- And return this handler -- If Result is Void, this means no handler was found. @@ -108,13 +108,13 @@ feature -- Traversing feature {NONE} -- Access: Implementation - source_uri (req: WGI_REQUEST): READABLE_STRING_32 + source_uri (req: WSF_REQUEST): READABLE_STRING_32 -- URI to use to find handler. do Result := req.path_info end - handler (req: WGI_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] + handler (req: WSF_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] -- Handler whose map matched with `req' require req_valid: source_uri (req) /= Void @@ -179,7 +179,7 @@ feature {NONE} -- Implementation deferred end - default_handler_context (req: WGI_REQUEST): C + default_handler_context (req: WSF_REQUEST): C -- Default handler context associated with `default_handler' require has_default_handler: default_handler /= Void diff --git a/library/server/request/router/src/request_routing_handler.e b/library/server/request/router/src/request_routing_handler.e index 19940f5f..d4519ef2 100644 --- a/library/server/request/router/src/request_routing_handler.e +++ b/library/server/request/router/src/request_routing_handler.e @@ -13,7 +13,7 @@ inherit feature -- Execution - execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE) -- Execute request handler local hdl: detachable H @@ -49,12 +49,12 @@ feature -- Mapping router.map_with_request_methods (a_resource, h, rqst_methods) end - map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]) + map_agent (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]) do router.map_agent (a_resource, a_action) end - map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + map_agent_with_request_methods (a_resource: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) do router.map_agent_with_request_methods (a_resource, a_action, rqst_methods) diff --git a/library/server/request/router/src/routed_application_i.e b/library/server/request/router/src/routed_application_i.e index eabefeb4..3c68daf1 100644 --- a/library/server/request/router/src/routed_application_i.e +++ b/library/server/request/router/src/routed_application_i.e @@ -35,7 +35,7 @@ feature -- Setup feature -- Execution - execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute (req: WSF_REQUEST; res: WSF_RESPONSE) local l_handled: BOOLEAN rescued: BOOLEAN @@ -50,11 +50,11 @@ feature -- Execution end end - execute_default (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) deferred end - execute_rescue (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + execute_rescue (req: WSF_REQUEST; res: WSF_RESPONSE) do if not res.header_committed then res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void) diff --git a/library/server/request/router/src/uri/default/request_uri_router.e b/library/server/request/router/src/uri/default/request_uri_router.e index 99c4d588..0cd35d9f 100644 --- a/library/server/request/router/src/uri/default/request_uri_router.e +++ b/library/server/request/router/src/uri/default/request_uri_router.e @@ -17,7 +17,7 @@ create feature -- Mapping - map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) local h: REQUEST_AGENT_HANDLER [REQUEST_URI_HANDLER_CONTEXT] diff --git a/library/server/request/router/src/uri/request_uri_handler_context.e b/library/server/request/router/src/uri/request_uri_handler_context.e index bfb167f1..543ac4d3 100644 --- a/library/server/request/router/src/uri/request_uri_handler_context.e +++ b/library/server/request/router/src/uri/request_uri_handler_context.e @@ -15,7 +15,7 @@ create feature {NONE} -- Initialization - make (req: WGI_REQUEST; p: like path) + make (req: WSF_REQUEST; p: like path) do request := req path := p @@ -23,11 +23,11 @@ feature {NONE} -- Initialization feature -- Query - path_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + path_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE do end - query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE do Result := request.query_parameter (a_name) end diff --git a/library/server/request/router/src/uri/request_uri_router_i.e b/library/server/request/router/src/uri/request_uri_router_i.e index 2bea6d90..c7cb069e 100644 --- a/library/server/request/router/src/uri/request_uri_router_i.e +++ b/library/server/request/router/src/uri/request_uri_router_i.e @@ -38,7 +38,7 @@ feature -- Registration feature {NONE} -- Access: Implementation - handler (req: WGI_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] + handler (req: WSF_REQUEST): detachable TUPLE [handler: H; context: like default_handler_context] local h: detachable H ctx: detachable like default_handler_context @@ -62,7 +62,7 @@ feature {NONE} -- Access: Implementation end end - smart_handler (req: WGI_REQUEST): detachable TUPLE [path: READABLE_STRING_8; handler: H] + smart_handler (req: WSF_REQUEST): detachable TUPLE [path: READABLE_STRING_8; handler: H] require req_valid: req /= Void and then source_uri (req) /= Void do @@ -124,7 +124,7 @@ feature {NONE} -- Access: Implementation feature {NONE} -- Context factory - handler_context (p: detachable STRING; req: WGI_REQUEST): C + handler_context (p: detachable STRING; req: WSF_REQUEST): C local ctx: C do @@ -184,7 +184,7 @@ feature {NONE} -- Default: implementation default_handler := h end - default_handler_context (req: WGI_REQUEST): C + default_handler_context (req: WSF_REQUEST): C do Result := handler_context (Void, req) end diff --git a/library/server/request/router/src/uri_template/default/request_uri_template_router.e b/library/server/request/router/src/uri_template/default/request_uri_template_router.e index 41cefe4f..3fef77bf 100644 --- a/library/server/request/router/src/uri_template/default/request_uri_template_router.e +++ b/library/server/request/router/src/uri_template/default/request_uri_template_router.e @@ -18,7 +18,7 @@ create feature -- Mapping - map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER]]; + map_agent_with_request_methods (a_id: READABLE_STRING_8; a_action: PROCEDURE [ANY, TUPLE [ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE]]; rqst_methods: detachable ARRAY [READABLE_STRING_8]) local h: REQUEST_AGENT_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT] diff --git a/library/server/request/router/src/uri_template/request_uri_template_handler_context.e b/library/server/request/router/src/uri_template/request_uri_template_handler_context.e index 5cf1c7db..2dc046c1 100644 --- a/library/server/request/router/src/uri_template/request_uri_template_handler_context.e +++ b/library/server/request/router/src/uri_template/request_uri_template_handler_context.e @@ -15,7 +15,7 @@ create feature {NONE} -- Initialization - make (req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT; p: like path) + make (req: WSF_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT; p: like path) do request := req uri_template := tpl @@ -31,17 +31,17 @@ feature -- Access feature -- Query - path_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + path_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE do if attached uri_template_match.url_decoded_path_variable (a_name) as s then - create {WGI_STRING_VALUE} Result.make (a_name, s) + create {WSF_STRING_VALUE} Result.make (a_name, s) end end - query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE do if attached uri_template_match.url_decoded_query_variable (a_name) as s then - create {WGI_STRING_VALUE} Result.make (a_name, s) + create {WSF_STRING_VALUE} Result.make (a_name, s) else Result := request.query_parameter (a_name) end diff --git a/library/server/request/router/src/uri_template/request_uri_template_router_i.e b/library/server/request/router/src/uri_template/request_uri_template_router_i.e index 9c3ec225..4e10389a 100644 --- a/library/server/request/router/src/uri_template/request_uri_template_router_i.e +++ b/library/server/request/router/src/uri_template/request_uri_template_router_i.e @@ -54,7 +54,7 @@ feature -- Registration feature {NONE} -- Access: Implementation - handler (req: WGI_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] + handler (req: WSF_REQUEST): detachable TUPLE [handler: attached like default_handler; context: like default_handler_context] local l_handlers: like handlers t: STRING @@ -94,7 +94,7 @@ feature {NONE} -- Access: Implementation feature {NONE} -- Context factory - handler_context (p: detachable STRING; req: WGI_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): C + handler_context (p: detachable STRING; req: WSF_REQUEST; tpl: URI_TEMPLATE; tpl_res: URI_TEMPLATE_MATCH_RESULT): C do if p /= Void then create Result.make (req, tpl, tpl_res, p) @@ -151,7 +151,7 @@ feature {NONE} -- Default: implementation default_handler := h end - default_handler_context (req: WGI_REQUEST): C + default_handler_context (req: WSF_REQUEST): C do Result := handler_context (Void, req, create {URI_TEMPLATE}.make ("/"), create {URI_TEMPLATE_MATCH_RESULT}.make_empty) end diff --git a/library/server/wsf/src/cgi_meta_names.e b/library/server/wsf/src/cgi_meta_names.e new file mode 100644 index 00000000..2d4621a7 --- /dev/null +++ b/library/server/wsf/src/cgi_meta_names.e @@ -0,0 +1,13 @@ +note + description: "Summary description for {WSF_META_NAMES}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CGI_META_NAMES + +inherit + WGI_META_NAMES + +end diff --git a/library/server/wsf/src/request/value/wsf_multiple_string_value.e b/library/server/wsf/src/request/value/wsf_multiple_string_value.e new file mode 100644 index 00000000..1325e67e --- /dev/null +++ b/library/server/wsf/src/request/value/wsf_multiple_string_value.e @@ -0,0 +1,143 @@ +note + description: "Summary description for {WSF_MULTIPLE_STRING_VALUE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_MULTIPLE_STRING_VALUE + +inherit + WSF_VALUE + + ITERABLE [WSF_STRING_VALUE] + +create + make_with_value, + make_with_array, + make_with_string + +feature {NONE} -- Initialization + + make_with_value (a_value: WSF_VALUE) + do + name := a_value.name + create {LINKED_LIST [WSF_STRING_VALUE]} string_values.make + add_value (a_value) + end + + make_with_array (arr: ARRAY [WSF_VALUE]) + require + arr_not_empty: not arr.is_empty + all_same_name: across arr as c all c.item.name.same_string (arr[arr.lower].name) end + local + i,up: INTEGER + do + up := arr.upper + i := arr.lower + make_with_value (arr[i]) + from + i := i + 1 + until + i > up + loop + add_value (arr[i]) + i := i + 1 + end + end + + make_with_string (a_name: like name; a_string: READABLE_STRING_32) + do + make_with_value (create {WSF_STRING_VALUE}.make (a_name, a_string)) + end + +feature -- Access + + name: READABLE_STRING_32 + + string_values: LIST [WSF_STRING_VALUE] + + first_string_value: WSF_STRING_VALUE + do + Result := string_values.first + end + +feature -- Traversing + + new_cursor: ITERATION_CURSOR [WSF_STRING_VALUE] + do + Result := string_values.new_cursor + end + +feature -- Helper + + same_string (a_other: READABLE_STRING_GENERAL): BOOLEAN + -- Does `a_other' represent the same string as `Current'? + do + if string_values.count = 1 then + Result := first_string_value.same_string (a_other) + end + end + + is_case_insensitive_equal (a_other: READABLE_STRING_8): BOOLEAN + -- Does `a_other' represent the same case insensitive string as `Current'? + do + if string_values.count = 1 then + Result := first_string_value.is_case_insensitive_equal (a_other) + end + end + + as_string: STRING_32 + do + if string_values.count = 1 then + create Result.make_from_string (first_string_value) + else + create Result.make_from_string ("[") + across + string_values as c + loop + if Result.count > 1 then + Result.append_character (',') + end + Result.append_string (c.item) + end + Result.append_character (']') + end + end + +feature -- Element change + + add_value (a_value: WSF_VALUE) + require + same_name: a_value.name.same_string (name) + do + if attached {WSF_STRING_VALUE} a_value as sval then + add_string_value (sval) + elseif attached {WSF_MULTIPLE_STRING_VALUE} a_value as slst then + across + slst as cur + loop + add_string_value (cur.item) + end + end + end + + add_string_value (s: WSF_STRING_VALUE) + do + string_values.extend (s) + end + +invariant + string_values_not_empty: string_values.count >= 1 + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/request/value/wsf_string_value.e b/library/server/wsf/src/request/value/wsf_string_value.e new file mode 100644 index 00000000..f72e794d --- /dev/null +++ b/library/server/wsf/src/request/value/wsf_string_value.e @@ -0,0 +1,71 @@ +note + description: "Summary description for {WSF_STRING_VALUE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_STRING_VALUE + +inherit + WSF_VALUE + +create + make + +convert + as_string: {READABLE_STRING_32, STRING_32} + +feature {NONE} -- Initialization + + make (a_name: READABLE_STRING_GENERAL; a_string: like string) + do + name := a_name.as_string_32 + string := a_string + end + +feature -- Access + + name: READABLE_STRING_32 + + string: READABLE_STRING_32 + +feature -- Helper + + same_string (a_other: READABLE_STRING_GENERAL): BOOLEAN + -- Does `a_other' represent the same string as `Current'? + do + Result := string.same_string_general (a_other) + end + + is_case_insensitive_equal (a_other: READABLE_STRING_8): BOOLEAN + -- Does `a_other' represent the same case insensitive string as `Current'? + local + v: like string + do + v := string + if v = a_other then + Result := True + elseif v.is_valid_as_string_8 then + Result := v.is_case_insensitive_equal (a_other) + end + end + +feature -- Conversion + + as_string: STRING_32 + do + create Result.make_from_string (string) + end + +;note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/request/wsf_value.e b/library/server/wsf/src/request/wsf_value.e new file mode 100644 index 00000000..b0bc9b35 --- /dev/null +++ b/library/server/wsf/src/request/wsf_value.e @@ -0,0 +1,59 @@ +note + description: "Summary description for {WSF_VALUE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_VALUE + +inherit + DEBUG_OUTPUT + +convert + as_string: {READABLE_STRING_32, STRING_32} + +feature -- Access + + name: READABLE_STRING_32 + -- Parameter name + deferred + end + +feature -- Helper + + same_string (a_other: READABLE_STRING_GENERAL): BOOLEAN + -- Does `a_other' represent the same string as `Current'? + deferred + end + + is_case_insensitive_equal (a_other: READABLE_STRING_8): BOOLEAN + -- Does `a_other' represent the same case insensitive string as `Current'? + deferred + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + create Result.make_from_string (name.as_string_8 + "=" + as_string.as_string_8) + end + +feature -- Query + + as_string: STRING_32 + deferred + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/support/wsf_error.e b/library/server/wsf/src/support/wsf_error.e new file mode 100644 index 00000000..d4f9eb47 --- /dev/null +++ b/library/server/wsf/src/support/wsf_error.e @@ -0,0 +1,66 @@ +note + description: "Summary description for {WSF_ERROR}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + WSF_ERROR + +inherit + ERROR + + HTTP_STATUS_CODE_MESSAGES + +create + make + +feature {NONE} -- Initialization + + make (a_code: INTEGER) + do + code := a_code + name := "HTTP Error" + if attached http_status_code_message (a_code) as m then + name := m + end + end + +feature -- Access + + code: INTEGER + + name: STRING + + message: detachable STRING_32 + +feature -- Element change + + set_message (m: like message) + -- Set `message' to `m' + require + m_attached: m /= Void + do + message := m + end + +feature -- Visitor + + process (a_visitor: ERROR_VISITOR) + -- Process Current using `a_visitor'. + do + a_visitor.process_error (Current) + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/support/wsf_header.e b/library/server/wsf/src/support/wsf_header.e new file mode 100644 index 00000000..ddc4a2be --- /dev/null +++ b/library/server/wsf/src/support/wsf_header.e @@ -0,0 +1,454 @@ +note + description: "[ + The class provides an easy way to build HTTP header. + + You will also find some helper feature to help coding most common usage + + Please, have a look at constants classes such as + HTTP_MIME_TYPES + HTTP_HEADER_NAMES + HTTP_STATUS_CODE + HTTP_REQUEST_METHODS + (or HTTP_CONSTANTS which groups them for convenience) + + Note the return status code is not part of the HTTP header + However you can set the "Status: " header line if you want + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + WSF_HEADER + +inherit + ANY + + HTTP_STATUS_CODE_MESSAGES --| useful for `put_status' + export + {NONE} all + end + +create + make, + make_with_count + +feature {NONE} -- Initialization + + make + -- Initialize current + do + make_with_count (3) + end + + make_with_count (n: INTEGER) + -- Make with a capacity of `n' header entries + do + create {ARRAYED_LIST [READABLE_STRING_8]} headers.make (n) + end + +feature -- Recycle + + recycle + -- Recycle current object + do + headers.wipe_out + end + +feature -- Access + + headers: LIST [READABLE_STRING_8] + -- Header's lines + + string: STRING + -- String representation of the headers + local + l_headers: like headers + do + create Result.make (32) + l_headers := headers + if l_headers.is_empty then + put_content_type_text_html -- See if this make sense to define a default content-type + else + from + l_headers.start + until + l_headers.after + loop + append_line_to (l_headers.item, Result) + l_headers.forth + end + end + append_end_of_line_to (Result) + end + +feature -- Header change: general + + add_header (h: READABLE_STRING_8) + -- Add header `h' + -- if it already exists, there will be multiple header with same name + -- which can also be valid + require + h_not_empty: not h.is_empty + do + headers.force (h) + end + + put_header (h: READABLE_STRING_8) + -- Add header `h' or replace existing header of same header name + require + h_not_empty: not h.is_empty + do + force_header_by_name (header_name (h), h) + end + + add_header_key_value (k,v: READABLE_STRING_8) + -- Add header `k:v', or replace existing header of same header name/key + do + add_header (k + colon_space + v) + end + + put_header_key_value (k,v: READABLE_STRING_8) + -- Add header `k:v', or replace existing header of same header name/key + do + put_header (k + colon_space + v) + end + +feature -- Status related + + put_status (c: INTEGER) + -- Put "Status: " header + -- Rarely used + local + s: STRING + do + create s.make_from_string (c.out) + if attached http_status_code_message (c) as msg then + s.append_character (' ') + s.append (msg) + end + put_header_key_value ("Status", s) + end + +feature -- Content related header + + put_content_type (t: READABLE_STRING_8) + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t) + end + + add_content_type (t: READABLE_STRING_8) + -- same as `put_content_type', but allow multiple definition of "Content-Type" + do + add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t) + end + + put_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8) + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; name=%"" + n + "%"") + end + + add_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8) + -- same as `put_content_type_with_name', but allow multiple definition of "Content-Type" + do + add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; name=%"" + n + "%"") + end + + put_content_length (n: INTEGER) + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_length, n.out) + end + + put_content_transfer_encoding (a_mechanism: READABLE_STRING_8) + -- Put "Content-Transfer-Encoding" header with for instance "binary" + --| encoding := "Content-Transfer-Encoding" ":" mechanism + --| + --| mechanism := "7bit" ; case-insensitive + --| / "quoted-printable" + --| / "base64" + --| / "8bit" + --| / "binary" + --| / x-token + + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_transfer_encoding, a_mechanism) + end + + put_transfer_encoding (a_enc: READABLE_STRING_8) + -- Put "Transfer-Encoding" header with for instance "chunked" + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_transfer_encoding, a_enc) + end + + put_transfer_encoding_chunked + -- Put "Transfer-Encoding: chunked" header + do + put_transfer_encoding ("chunked") + end + + put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8) + -- Put "Content-Disposition" header + --| See RFC2183 + --| disposition := "Content-Disposition" ":" + --| disposition-type + --| *(";" disposition-parm) + --| disposition-type := "inline" + --| / "attachment" + --| / extension-token + --| ; values are not case-sensitive + --| disposition-parm := filename-parm + --| / creation-date-parm + --| / modification-date-parm + --| / read-date-parm + --| / size-parm + --| / parameter + --| filename-parm := "filename" "=" value + --| creation-date-parm := "creation-date" "=" quoted-date-time + --| modification-date-parm := "modification-date" "=" quoted-date-time + --| read-date-parm := "read-date" "=" quoted-date-time + --| size-parm := "size" "=" 1*DIGIT + --| quoted-date-time := quoted-string + --| ; contents MUST be an RFC 822 `date-time' + --| ; numeric timezones (+HHMM or -HHMM) MUST be used + do + if a_params /= Void then + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type + semi_colon_space + a_params) + else + put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type) + end + end + +feature -- Content-type helpers + + put_content_type_text_css do put_content_type ({HTTP_MIME_TYPES}.text_css) end + put_content_type_text_csv do put_content_type ({HTTP_MIME_TYPES}.text_csv) end + put_content_type_text_html do put_content_type ({HTTP_MIME_TYPES}.text_html) end + put_content_type_text_javascript do put_content_type ({HTTP_MIME_TYPES}.text_javascript) end + put_content_type_text_json do put_content_type ({HTTP_MIME_TYPES}.text_json) end + put_content_type_text_plain do put_content_type ({HTTP_MIME_TYPES}.text_plain) end + put_content_type_text_xml do put_content_type ({HTTP_MIME_TYPES}.text_xml) end + + put_content_type_application_json do put_content_type ({HTTP_MIME_TYPES}.application_json) end + put_content_type_application_javascript do put_content_type ({HTTP_MIME_TYPES}.application_javascript) end + put_content_type_application_zip do put_content_type ({HTTP_MIME_TYPES}.application_zip) end + + put_content_type_image_gif do put_content_type ({HTTP_MIME_TYPES}.image_gif) end + put_content_type_image_png do put_content_type ({HTTP_MIME_TYPES}.image_png) end + put_content_type_image_jpg do put_content_type ({HTTP_MIME_TYPES}.image_jpg) end + put_content_type_image_svg_xml do put_content_type ({HTTP_MIME_TYPES}.image_svg_xml) end + + put_content_type_message_http do put_content_type ({HTTP_MIME_TYPES}.message_http) end + + put_content_type_multipart_mixed do put_content_type ({HTTP_MIME_TYPES}.multipart_mixed) end + put_content_type_multipart_alternative do put_content_type ({HTTP_MIME_TYPES}.multipart_alternative) end + put_content_type_multipart_related do put_content_type ({HTTP_MIME_TYPES}.multipart_related) end + put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end + put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end + put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end + +feature -- Date + + put_date (s: READABLE_STRING_8) + -- Put "Date: " header + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_date, s) + end + + put_current_date + -- Put current date time with "Date" header + do + put_utc_date (create {DATE_TIME}.make_now_utc) + end + + put_utc_date (dt: DATE_TIME) + -- Put UTC date time `dt' with "Date" header + do + put_date (dt.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT") + end + +feature -- Others + + put_expires (n: INTEGER) + do + put_header_key_value ("Expires", n.out) + end + + put_cache_control (s: READABLE_STRING_8) + -- `s' could be for instance "no-cache, must-revalidate" + do + put_header_key_value ("Cache-Control", s) + end + + put_pragma (s: READABLE_STRING_8) + do + put_header_key_value ("Pragma", s) + end + + put_pragma_no_cache + do + put_pragma ("no-cache") + end + +feature -- Redirection + + put_location (a_location: READABLE_STRING_8) + -- Tell the client the new location `a_location' + require + a_location_valid: not a_location.is_empty + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_location, a_location) + end + + put_refresh (a_location: READABLE_STRING_8; a_timeout_in_seconds: INTEGER) + -- Tell the client to refresh page with `a_location' after `a_timeout_in_seconds' in seconds + require + a_location_valid: not a_location.is_empty + do + put_header_key_value ({HTTP_HEADER_NAMES}.header_refresh, a_timeout_in_seconds.out + "; url=" + a_location) + end + +feature -- Cookie + + put_cookie (key, value: READABLE_STRING_8; expiration, path, domain, secure: detachable READABLE_STRING_8) + -- Set a cookie on the client's machine + -- with key 'key' and value 'value'. + require + make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty) + local + s: STRING + do + s := {HTTP_HEADER_NAMES}.header_set_cookie + colon_space + key + "=" + value + if expiration /= Void then + s.append ("; expires=" + expiration) + end + if path /= Void then + s.append ("; path=" + path) + end + if domain /= Void then + s.append ("; domain=" + domain) + end + if secure /= Void then + s.append ("; secure=" + secure) + end + add_header (s) + end + +feature -- Status report + + has_header_named (a_name: READABLE_STRING_8): BOOLEAN + -- Has header item for `n'? + local + c: like headers.new_cursor + n: INTEGER + l_line: READABLE_STRING_8 + do + from + n := a_name.count + c := headers.new_cursor + until + c.after or Result + loop + l_line := c.item + if l_line.starts_with (a_name) then + if l_line.valid_index (n + 1) then + Result := l_line [n + 1] = ':' + end + end + c.forth + end + end + + has_content_length: BOOLEAN + -- Has header "content_length" + do + Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length) + end + +feature {NONE} -- Implementation: Header + + force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8) + -- Add header `h' or replace existing header of same header name `n' + require + h_has_name_n: (n /= Void and attached header_name (h) as hn) implies n.same_string (hn) + local + l_headers: like headers + do + if n /= Void then + from + l_headers := headers + l_headers.start + until + l_headers.after or l_headers.item.starts_with (n) + loop + l_headers.forth + end + if not l_headers.after then + l_headers.replace (h) + else + add_header (h) + end + else + add_header (h) + end + end + + header_name (h: READABLE_STRING_8): detachable READABLE_STRING_8 + -- If any, header's name with colon + --| ex: for "Foo-bar: something", this will return "Foo-bar:" + local + s: detachable STRING_8 + i,n: INTEGER + c: CHARACTER + do + from + i := 1 + n := h.count + create s.make (10) + until + i > n or c = ':' or s = Void + loop + c := h[i] + inspect c + when ':' then + s.extend (c) + when '-', 'a' .. 'z', 'A' .. 'Z' then + s.extend (c) + else + s := Void + end + i := i + 1 + end + Result := s + end + +feature {NONE} -- Implementation + + append_line_to (s: READABLE_STRING_8; h: like string) + do + h.append_string (s) + append_end_of_line_to (h) + end + + append_end_of_line_to (h: like string) + do + h.append_character ('%R') + h.append_character ('%N') + end + +feature {NONE} -- Constants + + colon_space: STRING = ": " + semi_colon_space: STRING = "; " + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/server/wsf/src/wsf_application.e b/library/server/wsf/src/wsf_application.e new file mode 100644 index 00000000..2d845a04 --- /dev/null +++ b/library/server/wsf/src/wsf_application.e @@ -0,0 +1,32 @@ +note + description: "Objects that ..." + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_APPLICATION + +inherit + WGI_APPLICATION + rename + execute as wgi_execute + end + +feature -- Execution + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute the request + -- See `req.input' for input stream + -- `req.meta_variables' for the CGI meta variable + -- and `res' for output buffer + deferred + end + +feature -- WGI Execution + + wgi_execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) + do + execute (req, res) + end + +end diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e new file mode 100644 index 00000000..918f5ec8 --- /dev/null +++ b/library/server/wsf/src/wsf_request.e @@ -0,0 +1,1486 @@ +note + description: "[ + Summary description for {WSF_REQUEST}. + ]" + date: "$Date$" + revision: "$Revision$" + +class + WSF_REQUEST + +create {WSF_APPLICATION} + make_from_wgi + +convert + make_from_wgi ({WGI_REQUEST}) + +feature {NONE} -- Initialization + + make_from_wgi (r: WGI_REQUEST) + do + wgi_request := r + if attached r.meta_variables as l_vars then + create meta_variables_table.make (l_vars.count) + across + l_vars as c + loop + meta_variables_table.force (new_string_value (c.key, c.item), c.item) + end + else + create meta_variables_table.make (0) + end + meta_variables := meta_variables_table + create error_handler.make + create uploaded_files.make (0) + raw_post_data_recorded := True + create {STRING_32} empty_string.make_empty + + initialize + analyze + end + + initialize + -- Specific initialization + do + --| Here one can set its own environment entries if needed + if meta_variable ({CGI_META_NAMES}.request_time) = Void then + set_meta_string_variable ({CGI_META_NAMES}.request_time, date_time_utilities.unix_time_stamp (Void).out) + end + end + + wgi_request: WGI_REQUEST + +feature -- Status + + raw_post_data_recorded: BOOLEAN assign set_raw_post_data_recorded + -- Record RAW POST DATA in meta parameters + -- otherwise just forget about it + -- Default: true + --| warning: you might keep in memory big amount of memory ... + +feature -- Error handling + + has_error: BOOLEAN + do + Result := error_handler.has_error + end + + error_handler: ERROR_HANDLER + -- Error handler + -- By default initialized to new handler + +feature -- Access: Input + + input: WGI_INPUT_STREAM + -- Server input channel + do + Result := wgi_request.input + end + +feature {NONE} -- Access: global variable + + items_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL] + -- Table containing all the various variables + -- Warning: this is computed each time, if you change the content of other containers + -- this won't update this Result's content, unless you query it again + do + create Result.make (100) + + across + meta_variables as vars + loop + Result.force (vars.item, vars.item.name) + end + + across + query_parameters as vars + loop + Result.force (vars.item, vars.item.name) + end + + across + form_data_parameters as vars + loop + Result.force (vars.item, vars.item.name) + end + + across + cookies as vars + loop + Result.force (vars.item, vars.item.name) + end + + end + +feature -- Access: global variable + + items: ITERABLE [WSF_VALUE] + do + Result := items_table + end + + item (a_name: READABLE_STRING_8): detachable WSF_VALUE + -- Variable named `a_name' from any of the variables container + -- and following a specific order + -- execution, environment, get, post, cookies + local + v: detachable WSF_VALUE + do + v := meta_variable (a_name) + if v = Void then + v := query_parameter (a_name) + if v = Void then + v := form_data_parameter (a_name) + if v = Void then + v := cookie (a_name) + end + end + end +-- if s /= Void then +-- Result := s.as_string_32 +-- end + end + + string_item (a_name: READABLE_STRING_8): detachable READABLE_STRING_32 + do + if attached {WSF_STRING_VALUE} item (a_name) as val then + Result := val.string + else + check is_string_value: False end + end + end + +feature -- Access: CGI Meta variables + + meta_variable (a_name: READABLE_STRING_8): detachable WSF_STRING_VALUE + -- CGI Meta variable related to `a_name' + require + a_name_valid: a_name /= Void and then not a_name.is_empty + do + Result := meta_variables_table.item (a_name) + end + + meta_string_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_32 + -- CGI meta variable related to `a_name' + require + a_name_valid: a_name /= Void and then not a_name.is_empty + do + if attached meta_variable (a_name) as val then + Result := val.string + end + end + + meta_variables: ITERABLE [WSF_STRING_VALUE] + -- CGI meta variables values + + meta_string_variable_or_default (a_name: READABLE_STRING_8; a_default: READABLE_STRING_32; use_default_when_empty: BOOLEAN): READABLE_STRING_32 + -- Value for meta parameter `a_name' + -- If not found, return `a_default' + require + a_name_not_empty: a_name /= Void and then not a_name.is_empty + do + if attached meta_variable (a_name) as val then + Result := val.string + if use_default_when_empty and then Result.is_empty then + Result := a_default + end + else + Result := a_default + end + end + + set_meta_string_variable (a_name: READABLE_STRING_8; a_value: READABLE_STRING_32) + do + meta_variables_table.force (new_string_value (a_name, a_value), a_name) + ensure + param_set: attached {WSF_STRING_VALUE} meta_variable (a_name) as val and then val ~ a_value + end + + unset_meta_variable (a_name: READABLE_STRING_8) + do + meta_variables_table.remove (a_name) + ensure + param_unset: meta_variable (a_name) = Void + end + +feature {NONE} -- Access: CGI meta parameters + + meta_variables_table: HASH_TABLE [WSF_STRING_VALUE, READABLE_STRING_8] + -- CGI Environment parameters + +feature -- Access: CGI meta parameters - 1.1 + + auth_type: detachable READABLE_STRING_8 + -- This variable is specific to requests made via the "http" + -- scheme. + -- + -- If the Script-URI required access authentication for external + -- access, then the server MUST set the value of this variable + -- from the 'auth-scheme' token in the wgi_request's "Authorization" + -- header field. Otherwise it is set to NULL. + -- + -- AUTH_TYPE = "" | auth-scheme + -- auth-scheme = "Basic" | "Digest" | token + -- + -- HTTP access authentication schemes are described in section 11 + -- of the HTTP/1.1 specification [8]. The auth-scheme is not + -- case-sensitive. + -- + -- Servers MUST provide this metavariable to scripts if the + -- wgi_request header included an "Authorization" field that was + -- authenticated. + do + Result := wgi_request.auth_type + end + + content_length: detachable READABLE_STRING_8 + -- This metavariable is set to the size of the message-body + -- entity attached to the wgi_request, if any, in decimal number of + -- octets. If no data are attached, then this metavariable is + -- either NULL or not defined. The syntax is the same as for the + -- HTTP "Content-Length" header field (section 14.14, HTTP/1.1 + -- specification [8]). + -- + -- CONTENT_LENGTH = "" | 1*digit + -- + -- Servers MUST provide this metavariable to scripts if the + -- wgi_request was accompanied by a message-body entity. + do + Result := wgi_request.content_length + end + + content_length_value: NATURAL_64 + -- Integer value related to `content_length" + do +-- Result := wgi_request.content_length_value + check not_yet_implemented: False then end + end + + content_type: detachable READABLE_STRING_8 + -- If the wgi_request includes a message-body, CONTENT_TYPE is set to + -- the Internet Media Type [9] of the attached entity if the type + -- was provided via a "Content-type" field in the wgi_request header, + -- or if the server can determine it in the absence of a supplied + -- "Content-type" field. The syntax is the same as for the HTTP + -- "Content-Type" header field. + -- + -- CONTENT_TYPE = "" | media-type + -- media-type = type "/" subtype *( ";" parameter) + -- type = token + -- subtype = token + -- parameter = attribute "=" value + -- attribute = token + -- value = token | quoted-string + -- + -- The type, subtype, and parameter attribute names are not + -- case-sensitive. Parameter values MAY be case sensitive. Media + -- types and their use in HTTP are described in section 3.7 of + -- the HTTP/1.1 specification [8]. + -- + -- Example: + -- + -- application/x-www-form-urlencoded + -- + -- There is no default value for this variable. If and only if it + -- is unset, then the script MAY attempt to determine the media + -- type from the data received. If the type remains unknown, then + -- the script MAY choose to either assume a content-type of + -- application/octet-stream or reject the wgi_request with a 415 + -- ("Unsupported Media Type") error. See section 7.2.1.3 for more + -- information about returning error status values. + -- + -- Servers MUST provide this metavariable to scripts if a + -- "Content-Type" field was present in the original wgi_request + -- header. If the server receives a wgi_request with an attached + -- entity but no "Content-Type" header field, it MAY attempt to + -- determine the correct datatype, or it MAY omit this + -- metavariable when communicating the wgi_request information to the + -- script. + do + Result := wgi_request.content_type + end + + gateway_interface: READABLE_STRING_8 + -- This metavariable is set to the dialect of CGI being used by + -- the server to communicate with the script. Syntax: + -- + -- GATEWAY_INTERFACE = "CGI" "/" major "." minor + -- major = 1*digit + -- minor = 1*digit + -- + -- Note that the major and minor numbers are treated as separate + -- integers and hence each may be more than a single digit. Thus + -- CGI/2.4 is a lower version than CGI/2.13 which in turn is + -- lower than CGI/12.3. Leading zeros in either the major or the + -- minor number MUST be ignored by scripts and SHOULD NOT be + -- generated by servers. + -- + -- This document defines the 1.1 version of the CGI interface + -- ("CGI/1.1"). + -- + -- Servers MUST provide this metavariable to scripts. + -- + -- The version of the CGI specification to which this server + -- complies. Syntax: + -- + -- GATEWAY_INTERFACE = "CGI" "/" 1*digit "." 1*digit + -- + -- Note that the major and minor numbers are treated as separate + -- integers and that each may be incremented higher than a single + -- digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in + -- turn is lower than CGI/12.3. Leading zeros must be ignored by + -- scripts and should never be generated by servers. + do + Result := wgi_request.gateway_interface + end + + path_info: READABLE_STRING_8 + -- The PATH_INFO metavariable specifies a path to be interpreted + -- by the CGI script. It identifies the resource or sub-resource + -- to be returned by the CGI script, and it is derived from the + -- portion of the URI path following the script name but + -- preceding any query data. The syntax and semantics are similar + -- to a decoded HTTP URL 'path' token (defined in RFC 2396 [4]), + -- with the exception that a PATH_INFO of "/" represents a single + -- void path segment. + -- + -- PATH_INFO = "" | ( "/" path ) + -- path = segment *( "/" segment ) + -- segment = *pchar + -- pchar = + -- + -- The PATH_INFO string is the trailing part of the + -- component of the Script-URI (see section 3.2) that follows the + -- SCRIPT_NAME portion of the path. + -- + -- Servers MAY impose their own restrictions and limitations on + -- what values they will accept for PATH_INFO, and MAY reject or + -- edit any values they consider objectionable before passing + -- them to the script. + -- + -- Servers MUST make this URI component available to CGI scripts. + -- The PATH_INFO value is case-sensitive, and the server MUST + -- preserve the case of the PATH_INFO element of the URI when + -- making it available to scripts. + do + Result := wgi_request.path_info + end + + path_translated: detachable READABLE_STRING_8 + -- PATH_TRANSLATED is derived by taking any path-info component + -- of the wgi_request URI (see section 6.1.6), decoding it (see + -- section 3.1), parsing it as a URI in its own right, and + -- performing any virtual-to-physical translation appropriate to + -- map it onto the server's document repository structure. If the + -- wgi_request URI includes no path-info component, the + -- PATH_TRANSLATED metavariable SHOULD NOT be defined. + -- + -- + -- PATH_TRANSLATED = *CHAR + -- + -- For a wgi_request such as the following: + -- + -- http://somehost.com/cgi-bin/somescript/this%2eis%2epath%2einfo + -- + -- the PATH_INFO component would be decoded, and the result + -- parsed as though it were a wgi_request for the following: + -- + -- http://somehost.com/this.is.the.path.info + -- + -- This would then be translated to a location in the server's + -- document repository, perhaps a filesystem path something like + -- this: + -- + -- /usr/local/www/htdocs/this.is.the.path.info + -- + -- The result of the translation is the value of PATH_TRANSLATED. + -- + -- The value of PATH_TRANSLATED may or may not map to a valid + -- repository location. Servers MUST preserve the case of the + -- path-info segment if and only if the underlying repository + -- supports case-sensitive names. If the repository is only + -- case-aware, case-preserving, or case-blind with regard to + -- document names, servers are not required to preserve the case + -- of the original segment through the translation. + -- + -- The translation algorithm the server uses to derive + -- PATH_TRANSLATED is implementation defined; CGI scripts which + -- use this variable may suffer limited portability. + -- + -- Servers SHOULD provide this metavariable to scripts if and + -- only if the wgi_request URI includes a path-info component. + do + Result := wgi_request.path_translated + end + + query_string: READABLE_STRING_8 + -- A URL-encoded string; the part of the Script-URI. (See + -- section 3.2.) + -- + -- QUERY_STRING = query-string + -- query-string = *uric + + -- The URL syntax for a query string is described in section 3 of + -- RFC 2396 [4]. + -- + -- Servers MUST supply this value to scripts. The QUERY_STRING + -- value is case-sensitive. If the Script-URI does not include a + -- query component, the QUERY_STRING metavariable MUST be defined + -- as an empty string (""). + do + Result := wgi_request.query_string + end + + remote_addr: READABLE_STRING_8 + -- The IP address of the client sending the wgi_request to the + -- server. This is not necessarily that of the user agent (such + -- as if the wgi_request came through a proxy). + -- + -- REMOTE_ADDR = hostnumber + -- hostnumber = ipv4-address | ipv6-address + + -- The definitions of ipv4-address and ipv6-address are provided + -- in Appendix B of RFC 2373 [13]. + -- + -- Servers MUST supply this value to scripts. + do + Result := wgi_request.remote_addr + end + + remote_host: detachable READABLE_STRING_8 + -- The fully qualified domain name of the client sending the + -- wgi_request to the server, if available, otherwise NULL. (See + -- section 6.1.9.) Fully qualified domain names take the form as + -- described in section 3.5 of RFC 1034 [10] and section 2.1 of + -- RFC 1123 [5]. Domain names are not case sensitive. + -- + -- Servers SHOULD provide this information to scripts. + do + Result := wgi_request.remote_host + end + + remote_ident: detachable READABLE_STRING_8 + -- The identity information reported about the connection by a + -- RFC 1413 [11] wgi_request to the remote agent, if available. + -- Servers MAY choose not to support this feature, or not to + -- wgi_request the data for efficiency reasons. + -- + -- REMOTE_IDENT = *CHAR + -- + -- The data returned may be used for authentication purposes, but + -- the level of trust reposed in them should be minimal. + -- + -- Servers MAY supply this information to scripts if the RFC1413 + -- [11] lookup is performed. + do + Result := wgi_request.remote_ident + end + + remote_user: detachable READABLE_STRING_8 + -- If the wgi_request required authentication using the "Basic" + -- mechanism (i.e., the AUTH_TYPE metavariable is set to + -- "Basic"), then the value of the REMOTE_USER metavariable is + -- set to the user-ID supplied. In all other cases the value of + -- this metavariable is undefined. + -- + -- REMOTE_USER = *OCTET + -- + -- This variable is specific to requests made via the HTTP + -- protocol. + -- + -- Servers SHOULD provide this metavariable to scripts. + do + Result := wgi_request.remote_user + end + + request_method: READABLE_STRING_8 + -- The REQUEST_METHOD metavariable is set to the method with + -- which the wgi_request was made, as described in section 5.1.1 of + -- the HTTP/1.0 specification [3] and section 5.1.1 of the + -- HTTP/1.1 specification [8]. + -- + -- REQUEST_METHOD = http-method + -- http-method = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" + -- | "OPTIONS" | "TRACE" | extension-method + -- extension-method = token + -- + -- The method is case sensitive. CGI/1.1 servers MAY choose to + -- process some methods directly rather than passing them to + -- scripts. + -- + -- This variable is specific to requests made with HTTP. + -- + -- Servers MUST provide this metavariable to scripts. + do + Result := wgi_request.request_method + end + + script_name: READABLE_STRING_8 + -- The SCRIPT_NAME metavariable is set to a URL path that could + -- identify the CGI script (rather than the script's output). The + -- syntax and semantics are identical to a decoded HTTP URL + -- 'path' token (see RFC 2396 [4]). + -- + -- SCRIPT_NAME = "" | ( "/" [ path ] ) + -- + -- The SCRIPT_NAME string is some leading part of the + -- component of the Script-URI derived in some implementation + -- defined manner. No PATH_INFO or QUERY_STRING segments (see + -- sections 6.1.6 and 6.1.8) are included in the SCRIPT_NAME + -- value. + -- + -- Servers MUST provide this metavariable to scripts. + do + Result := wgi_request.script_name + end + + server_name: READABLE_STRING_8 + -- The SERVER_NAME metavariable is set to the name of the server, + -- as derived from the part of the Script-URI (see section + -- 3.2). + -- + -- SERVER_NAME = hostname | hostnumber + -- + -- Servers MUST provide this metavariable to scripts. + do + Result := wgi_request.server_name + end + + server_port: INTEGER + -- The SERVER_PORT metavariable is set to the port on which the + -- wgi_request was received, as used in the part of the + -- Script-URI. + -- + -- SERVER_PORT = 1*digit + -- + -- If the portion of the script-URI is blank, the actual + -- port number upon which the wgi_request was received MUST be + -- supplied. + -- + -- Servers MUST provide this metavariable to scripts. + do + Result := wgi_request.server_port + end + + server_protocol: READABLE_STRING_8 + -- The SERVER_PROTOCOL metavariable is set to the name and + -- revision of the information protocol with which the wgi_request + -- arrived. This is not necessarily the same as the protocol + -- version used by the server in its response to the client. + -- + -- SERVER_PROTOCOL = HTTP-Version | extension-version + -- | extension-token + -- HTTP-Version = "HTTP" "/" 1*digit "." 1*digit + -- extension-version = protocol "/" 1*digit "." 1*digit + -- protocol = 1*( alpha | digit | "+" | "-" | "." ) + -- extension-token = token + -- + -- 'protocol' is a version of the part of the + -- Script-URI, but is not identical to it. For example, the + -- scheme of a wgi_request may be "https" while the protocol remains + -- "http". The protocol is not case sensitive, but by convention, + -- 'protocol' is in upper case. + -- + -- A well-known extension token value is "INCLUDED", which + -- signals that the current document is being included as part of + -- a composite document, rather than being the direct target of + -- the client wgi_request. + -- + -- Servers MUST provide this metavariable to scripts. + do + check not_yet_implemented: False then end +-- Result := wgi_request.server_protocol + end + + server_software: READABLE_STRING_8 + -- The SERVER_SOFTWARE metavariable is set to the name and + -- version of the information server software answering the + -- wgi_request (and running the gateway). + -- + -- SERVER_SOFTWARE = 1*product + -- product = token [ "/" product-version ] + -- product-version = token + + -- Servers MUST provide this metavariable to scripts. + do + check not_yet_implemented: False then end +-- Result := wgi_request.server_software + end + +feature -- HTTP_* + + http_accept: detachable READABLE_STRING_8 + -- Contents of the Accept: header from the current wgi_request, if there is one. + -- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + do + Result := wgi_request.http_accept + end + + http_accept_charset: detachable READABLE_STRING_8 + -- Contents of the Accept-Charset: header from the current wgi_request, if there is one. + -- Example: 'iso-8859-1,*,utf-8'. + do + Result := wgi_request.http_accept_charset + end + + http_accept_encoding: detachable READABLE_STRING_8 + -- Contents of the Accept-Encoding: header from the current wgi_request, if there is one. + -- Example: 'gzip'. + do + Result := wgi_request.http_accept_encoding + end + + http_accept_language: detachable READABLE_STRING_8 + -- Contents of the Accept-Language: header from the current wgi_request, if there is one. + -- Example: 'en'. + do + Result := wgi_request.http_accept_language + end + + http_connection: detachable READABLE_STRING_8 + -- Contents of the Connection: header from the current wgi_request, if there is one. + -- Example: 'Keep-Alive'. + do + Result := wgi_request.http_connection + end + + http_host: detachable READABLE_STRING_8 + -- Contents of the Host: header from the current wgi_request, if there is one. + do + Result := wgi_request.http_host + end + + http_referer: detachable READABLE_STRING_8 + -- The address of the page (if any) which referred the user agent to the current page. + -- This is set by the user agent. + -- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. + -- In short, it cannot really be trusted. + do + Result := wgi_request.http_referer + end + + http_user_agent: detachable READABLE_STRING_8 + -- Contents of the User-Agent: header from the current wgi_request, if there is one. + -- This is a string denoting the user agent being which is accessing the page. + -- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). + -- Among other things, you can use this value to tailor your page's + -- output to the capabilities of the user agent. + do + Result := wgi_request.http_user_agent + end + + http_authorization: detachable READABLE_STRING_8 + -- Contents of the Authorization: header from the current wgi_request, if there is one. + do + Result := wgi_request.http_authorization + end + +feature -- Extra CGI environment variables + + request_uri: READABLE_STRING_8 + -- The URI which was given in order to access this page; for instance, '/index.html'. + do + Result := wgi_request.request_uri + end + + orig_path_info: detachable READABLE_STRING_8 + -- Original version of `path_info' before processed by Current environment + do + Result := wgi_request.orig_path_info + end + + request_time: detachable DATE_TIME + -- Request time (UTC) + do + if + attached {WSF_STRING_VALUE} meta_variable ({CGI_META_NAMES}.request_time) as t and then + t.string.is_integer_64 + then + Result := date_time_utilities.unix_time_stamp_to_date_time (t.string.to_integer_64) + end + end + +feature -- Cookies + + cookies: ITERABLE [WSF_VALUE] + do + Result := cookies_table + end + + cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE + -- Field for name `a_name'. + do + Result := cookies_table.item (a_name) + end + +feature {NONE} -- Cookies + + cookies_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL] + -- Expanded cookies variable + local + i,j,p,n: INTEGER + l_cookies: like internal_cookies_table + k,v,s: STRING + do + l_cookies := internal_cookies_table + if l_cookies = Void then + if attached {WSF_STRING_VALUE} meta_variable ({CGI_META_NAMES}.http_cookie) as val then + s := val.string + create l_cookies.make (5) + l_cookies.compare_objects + from + n := s.count + p := 1 + i := 1 + until + p < 1 + loop + i := s.index_of ('=', p) + if i > 0 then + j := s.index_of (';', i) + if j = 0 then + j := n + 1 + k := s.substring (p, i - 1) + v := s.substring (i + 1, n) + + p := 0 -- force termination + else + k := s.substring (p, i - 1) + v := s.substring (i + 1, j - 1) + p := j + 1 + end + l_cookies.force (new_string_value (k, v), k) + end + end + else + create l_cookies.make (0) + l_cookies.compare_objects + end + internal_cookies_table := l_cookies + end + Result := l_cookies + end + +feature -- Query parameters + + query_parameters: ITERABLE [WSF_VALUE] + do + Result := query_parameters_table + end + + query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE + -- Parameter for name `n'. + do + Result := query_parameters_table.item (a_name) + end + +feature {NONE} -- Query parameters: implementation + + query_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL] + -- Variables extracted from QUERY_STRING + local + vars: like internal_query_parameters_table + p,e: INTEGER + rq_uri: like request_uri + s: detachable STRING + do + vars := internal_query_parameters_table + if vars = Void then + s := query_string + if s = Void then + rq_uri := request_uri + p := rq_uri.index_of ('?', 1) + if p > 0 then + e := rq_uri.index_of ('#', p + 1) + if e = 0 then + e := rq_uri.count + else + e := e - 1 + end + s := rq_uri.substring (p+1, e) + end + end + vars := urlencoded_parameters (s, True) + vars.compare_objects + internal_query_parameters_table := vars + end + Result := vars + end + + urlencoded_parameters (a_content: detachable READABLE_STRING_8; decoding: BOOLEAN): HASH_TABLE [WSF_VALUE, STRING] + -- Import `a_content' + local + n, p, i, j: INTEGER + s: STRING + l_name,l_value: STRING_32 + v: WSF_VALUE + do + if a_content = Void then + create Result.make (0) + else + n := a_content.count + if n = 0 then + create Result.make (0) + else + create Result.make (3) + from + p := 1 + until + p = 0 + loop + i := a_content.index_of ('&', p) + if i = 0 then + s := a_content.substring (p, n) + p := 0 + else + s := a_content.substring (p, i - 1) + p := i + 1 + end + if not s.is_empty then + j := s.index_of ('=', 1) + if j > 0 then + l_name := s.substring (1, j - 1) + l_value := s.substring (j + 1, s.count) + if decoding then + l_name := url_encoder.decoded_string (l_name) + l_value := url_encoder.decoded_string (l_value) + end + v := new_string_value (l_name, l_value) + if Result.has_key (l_name) and then attached Result.found_item as l_existing_value then + if attached {WSF_MULTIPLE_STRING_VALUE} l_existing_value as l_multi then + l_multi.add_value (v) + else + Result.force (create {WSF_MULTIPLE_STRING_VALUE}.make_with_array (<>), l_name) + check replaced: Result.found and then Result.found_item ~ l_existing_value end + end + else + Result.force (v, l_name) + end + end + end + end + end + end + end + +feature -- Form fields and related + + form_data_parameters: ITERABLE [WSF_VALUE] + do + Result := form_data_parameters_table + end + + form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE + -- Field for name `a_name'. + do + Result := form_data_parameters_table.item (a_name) + end + + uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, STRING] + -- Table of uploaded files information + --| name: original path from the user + --| type: content type + --| tmp_name: path to temp file that resides on server + --| tmp_base_name: basename of `tmp_name' + --| error: if /= 0 , there was an error : TODO ... + --| size: size of the file given by the http request + +feature {NONE} -- Form fields and related + + form_data_parameters_table: HASH_TABLE [WSF_VALUE, READABLE_STRING_GENERAL] + -- Variables sent by POST request + local + vars: like internal_form_data_parameters_table + s: STRING + n: NATURAL_64 + l_type: like content_type + do + vars := internal_form_data_parameters_table + if vars = Void then + n := content_length_value + if n > 0 then + l_type := content_type + if + l_type /= Void and then + l_type.starts_with ({HTTP_MIME_TYPES}.multipart_form_data) + then + create vars.make (5) + vars.compare_objects + --| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ... + s := form_input_data (n.to_integer_32) --| FIXME truncated from NAT64 to INT32 + analyze_multipart_form (l_type, s, vars) + else + s := form_input_data (n.to_integer_32) --| FIXME truncated from NAT64 to INT32 + vars := urlencoded_parameters (s, True) + end + if raw_post_data_recorded then + set_meta_string_variable ("RAW_POST_DATA", s) + end + else + create vars.make (0) + vars.compare_objects + end + internal_form_data_parameters_table := vars + end + Result := vars + end + +feature -- Uploaded File Handling + + is_uploaded_file (a_filename: STRING): BOOLEAN + -- Is `a_filename' a file uploaded via HTTP Form + local + l_files: like uploaded_files + do + l_files := uploaded_files + if not l_files.is_empty then + from + l_files.start + until + l_files.after or Result + loop + if attached l_files.item_for_iteration.tmp_name as l_tmp_name and then l_tmp_name.same_string (a_filename) then + Result := True + end + l_files.forth + end + end + end + +feature -- URL Utility + + absolute_script_url (a_path: STRING): STRING + -- Absolute Url for the script if any, extended by `a_path' + do + Result := script_url (a_path) + if attached http_host as h then + Result.prepend (h) + Result.prepend ("http://") + else + --| Issue ?? + end + end + + script_url (a_path: STRING): STRING + -- Url relative to script name if any, extended by `a_path' + local + l_base_url: like internal_url_base + i,m,n: INTEGER + l_rq_uri: like request_uri + do + l_base_url := internal_url_base + if l_base_url = Void then + if attached script_name as l_script_name then + l_rq_uri := request_uri + if l_rq_uri.starts_with (l_script_name) then + l_base_url := l_script_name + else + --| Handle Rewrite url engine, to have clean path + from + i := 1 + m := l_rq_uri.count + n := l_script_name.count + until + i > m or i > n or l_rq_uri[i] /= l_script_name[i] + loop + i := i + 1 + end + if i > 1 then + if l_rq_uri[i-1] = '/' then + i := i -1 + end + l_base_url := l_rq_uri.substring (1, i - 1) + end + end + end + if l_base_url = Void then + create l_base_url.make_empty + end + internal_url_base := l_base_url + end + Result := l_base_url + a_path + end + +feature {NONE} -- Implementation: URL Utility + + internal_url_base: detachable STRING + -- URL base of potential script + +feature -- Element change + + set_raw_post_data_recorded (b: BOOLEAN) + -- Set `raw_post_data_recorded' to `b' + do + raw_post_data_recorded := b + end + + set_error_handler (ehdl: like error_handler) + -- Set `error_handler' to `ehdl' + do + error_handler := ehdl + end + +feature {NONE} -- Temporary File handling + + delete_uploaded_file (uf: WGI_UPLOADED_FILE_DATA) + -- Delete file `a_filename' + require + uf_valid: uf /= Void + local + f: RAW_FILE + do + if uploaded_files.has_item (uf) then + if attached uf.tmp_name as fn then + create f.make (fn) + if f.exists and then f.is_writable then + f.delete + else + error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete file %""+ fn +"%"") + end + else + error_handler.add_custom_error (0, "Can not delete uploaded file", "Can not delete uploaded file %""+ uf.name +"%" Tmp File not found") + end + else + error_handler.add_custom_error (0, "Not an uploaded file", "This file %""+ uf.name +"%" is not an uploaded file.") + end + end + + save_uploaded_file (a_content: STRING; a_up_fn_info: WGI_UPLOADED_FILE_DATA) + -- Save uploaded file content to `a_filename' + local + bn: STRING + l_safe_name: STRING + f: RAW_FILE + dn: STRING + fn: FILE_NAME + d: DIRECTORY + n: INTEGER + rescued: BOOLEAN + do + if not rescued then + dn := (create {EXECUTION_ENVIRONMENT}).current_working_directory + create d.make (dn) + if d.exists and then d.is_writable then + l_safe_name := safe_filename (a_up_fn_info.name) + from + create fn.make_from_string (dn) + bn := "tmp-" + l_safe_name + fn.set_file_name (bn) + create f.make (fn.string) + n := 0 + until + not f.exists + or else n > 1_000 + loop + n := n + 1 + fn.make_from_string (dn) + bn := "tmp-" + n.out + "-" + l_safe_name + fn.set_file_name (bn) + f.make (fn.string) + end + + if not f.exists or else f.is_writable then + a_up_fn_info.set_tmp_name (f.name) + a_up_fn_info.set_tmp_basename (bn) + f.open_write + f.put_string (a_content) + f.close + else + a_up_fn_info.set_error (-1) + end + else + error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"") + end + else + a_up_fn_info.set_error (-1) + end + rescue + rescued := True + retry + end + + safe_filename (fn: STRING): STRING + local + c: CHARACTER + i, n, p: INTEGER + l_accentued, l_non_accentued: STRING + do + l_accentued := "ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ" + l_non_accentued := "AAAAAACEEEEIIIIOOOOOUUUUYaaaaaaceeeeiiiioooooouuuuyy" + + --| Compute safe filename, to avoid creating impossible filename, or dangerous one + from + i := 1 + n := fn.count + create Result.make (n) + until + i > n + loop + c := fn[i] + inspect c + when '.', '-', '_' then + Result.extend (c) + when 'A' .. 'Z', 'a' .. 'z', '0' .. '9' then + Result.extend (c) + else + p := l_accentued.index_of (c, 1) + if p > 0 then + Result.extend (l_non_accentued[p]) + else + Result.extend ('-') + end + end + i := i + 1 + end + end + +feature {NONE} -- Implementation: Form analyzer + + analyze_multipart_form (t: STRING; s: STRING; vars: like form_data_parameters_table) + -- Analyze multipart form content + --| FIXME[2011-06-21]: integrate eMIME parser library + require + t_attached: t /= Void + s_attached: s /= Void + vars_attached: vars /= Void + local + p,i,next_b: INTEGER + l_boundary_prefix: STRING + l_boundary: STRING + l_boundary_len: INTEGER + m: STRING + is_crlf: BOOLEAN + do + p := t.substring_index ("boundary=", 1) + if p > 0 then + l_boundary := t.substring (p + 9, t.count) + p := s.substring_index (l_boundary, 1) + if p > 1 then + l_boundary_prefix := s.substring (1, p - 1) + l_boundary := l_boundary_prefix + l_boundary + else + create l_boundary_prefix.make_empty + end + l_boundary_len := l_boundary.count + --| Let's support either %R%N and %N ... + --| Since both cases might occurs (for instance, our implementation of CGI does not have %R%N) + --| then let's be as flexible as possible on this. + is_crlf := s[l_boundary_len + 1] = '%R' + from + i := 1 + l_boundary_len + 1 + if is_crlf then + i := i + 1 --| +1 = CR = %R + end + next_b := i + until + i = 0 + loop + next_b := s.substring_index (l_boundary, i) + if next_b > 0 then + if is_crlf then + m := s.substring (i, next_b - 1 - 2) --| 2 = CR LF = %R %N + else + m := s.substring (i, next_b - 1 - 1) --| 1 = LF = %N + end + analyze_multipart_form_input (m, vars) + i := next_b + l_boundary_len + 1 + if is_crlf then + i := i + 1 --| +1 = CR = %R + end + else + if is_crlf then + i := i + 1 + end + m := s.substring (i - 1, s.count) + m.right_adjust + if not l_boundary_prefix.same_string (m) then + error_handler.add_custom_error (0, "Invalid form data", "Invalid ending for form data from input") + end + i := next_b + end + end + end + end + + analyze_multipart_form_input (s: STRING; vars_post: like form_data_parameters_table) + -- Analyze multipart entry + require + s_not_empty: s /= Void and then not s.is_empty + local + n, i,p, b,e: INTEGER + l_name, l_filename, l_content_type: detachable STRING + l_header: detachable STRING + l_content: detachable STRING + l_line: detachable STRING + l_up_file_info: WGI_UPLOADED_FILE_DATA + do + from + p := 1 + n := s.count + until + p > n or l_header /= Void + loop + inspect s[p] + when '%R' then -- CR + if + n >= p + 3 and then + s[p+1] = '%N' and then -- LF + s[p+2] = '%R' and then -- CR + s[p+3] = '%N' -- LF + then + l_header := s.substring (1, p + 1) + l_content := s.substring (p + 4, n) + end + when '%N' then + if + n >= p + 1 and then + s[p+1] = '%N' + then + l_header := s.substring (1, p) + l_content := s.substring (p + 2, n) + end + else + end + p := p + 1 + end + if l_header /= Void and l_content /= Void then + from + i := 1 + n := l_header.count + until + i = 0 or i > n + loop + l_line := Void + b := i + p := l_header.index_of ('%N', b) + if p > 0 then + if l_header[p - 1] = '%R' then + p := p - 1 + i := p + 2 + else + i := p + 1 + end + end + if p > 0 then + l_line := l_header.substring (b, p - 1) + if l_line.starts_with ("Content-Disposition: form-data") then + p := l_line.substring_index ("name=", 1) + if p > 0 then + p := p + 4 --| 4 = ("name=").count - 1 + if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then + p := p + 1 + e := l_line.index_of ('"', p + 1) + else + e := l_line.index_of (';', p + 1) + if e = 0 then + e := l_line.count + end + end + l_name := l_header.substring (p + 1, e - 1) + end + + p := l_line.substring_index ("filename=", 1) + if p > 0 then + p := p + 8 --| 8 = ("filename=").count - 1 + if l_line.valid_index (p+1) and then l_line[p+1] = '%"' then + p := p + 1 + e := l_line.index_of ('"', p + 1) + else + e := l_line.index_of (';', p + 1) + if e = 0 then + e := l_line.count + end + end + l_filename := l_header.substring (p + 1, e - 1) + end + elseif l_line.starts_with ("Content-Type: ") then + l_content_type := l_line.substring (15, l_line.count) + end + else + i := 0 + end + end + if l_name /= Void then + if l_filename /= Void then + if l_content_type = Void then + l_content_type := default_content_type + end + create l_up_file_info.make (l_filename, l_content_type, l_content.count) + save_uploaded_file (l_content, l_up_file_info) + uploaded_files.force (l_up_file_info, l_name) + else + vars_post.force (new_string_value (l_name, l_content), l_name) + end + else + error_handler.add_custom_error (0, "unamed multipart entry", Void) + end + else + error_handler.add_custom_error (0, "missformed multipart entry", Void) + end + end + +feature {NONE} -- Internal value + + default_content_type: STRING = "text/plain" + -- Default content type + + form_input_data (nb: INTEGER): STRING + -- data from input form + local + n: INTEGER + t: STRING + do + from + n := nb + create Result.make (n) + if n > 1_024 then + n := 1_024 + end + until + n <= 0 + loop + read_input (n) + t := last_input_string + Result.append_string (t) + if t.count < n then + n := 0 + end + n := nb - t.count + end + end + + internal_query_parameters_table: detachable like query_parameters_table + -- cached value for `query_parameters' + + internal_form_data_parameters_table: detachable like form_data_parameters_table + -- cached value for `form_fields' + + internal_cookies_table: detachable like cookies_table + -- cached value for `cookies' + +feature {NONE} -- I/O: implementation + + read_input (nb: INTEGER) + -- Read `nb' bytes from `input' + do + input.read_stream (nb) + end + + last_input_string: STRING + -- Last string read from `input' + do + Result := input.last_string + end + +feature {NONE} -- Implementation + + report_bad_request_error (a_message: detachable STRING) + -- Report error + local + e: EWF_ERROR + do + create e.make ({HTTP_STATUS_CODE}.bad_request) + if a_message /= Void then + e.set_message (a_message) + end + error_handler.add_error (e) + end + + analyze + -- Extract relevant meta parameters + local + s: detachable READABLE_STRING_8 + do + s := request_uri + if s.is_empty then + report_bad_request_error ("Missing URI") + end + if not has_error then + s := request_method + if s.is_empty then + report_bad_request_error ("Missing request method") + end + end + if not has_error then + s := http_host + if s = Void or else s.is_empty then + report_bad_request_error ("Missing host header") + end + end +-- if not has_error then +-- update_path_info +-- end + end + +feature {NONE} -- Implementation: utilities + + single_slash_starting_string (s: READABLE_STRING_32): STRING_32 + -- Return the string `s' (or twin) with one and only one starting slash + local + i, n: INTEGER + do + n := s.count + if n > 1 then + if s[1] /= '/' then + create Result.make (1 + n) + Result.append_character ('/') + Result.append (s) + elseif s[2] = '/' then + --| We need to remove all starting slash, except one + from + i := 3 + until + i > n + loop + if s[i] /= '/' then + n := 0 --| exit loop + else + i := i + 1 + end + end + n := s.count + check i >= 2 and i <= n end + Result := s.substring (i - 1, s.count) + else + --| starts with one '/' and only one + Result := s + end + elseif n = 1 then + if s[1] = '/' then + Result := s + else + create Result.make (2) + Result.append_character ('/') + Result.append (s) + end + else --| n = 0 + create Result.make_filled ('/', 1) + end + ensure + one_starting_slash: Result[1] = '/' and (Result.count = 1 or else Result[2] /= '/') + end + + new_string_value (a_name: READABLE_STRING_GENERAL; a_value: READABLE_STRING_32): WSF_STRING_VALUE + do + create Result.make (a_name, a_value) + end + + empty_string: READABLE_STRING_32 + -- Reusable empty string + + url_encoder: URL_ENCODER + once + create Result + end + + date_time_utilities: HTTP_DATE_TIME_UTILITIES + -- Utilities classes related to date and time. + once + create Result + end + +invariant + empty_string_unchanged: empty_string.is_empty + + +end diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e new file mode 100644 index 00000000..13f6278e --- /dev/null +++ b/library/server/wsf/src/wsf_response.e @@ -0,0 +1,164 @@ +note + description: "[ + Summary description for {WSF_RESPONSE}. + ]" + date: "$Date$" + revision: "$Revision$" + +class + WSF_RESPONSE + +create {WSF_APPLICATION} + make_from_wgi + +convert + make_from_wgi ({WGI_RESPONSE_BUFFER}) + +feature {NONE} -- Initialization + + make_from_wgi (r: WGI_RESPONSE_BUFFER) + do + wgi_response := r + end + + wgi_response: WGI_RESPONSE_BUFFER + +--feature {WSF_APPLICATION} -- Commit + +-- commit +-- -- Commit the current response +-- do +-- wgi_response.commit +-- ensure +-- status_is_set: status_is_set +-- header_committed: header_committed +-- message_committed: message_committed +-- end + +feature -- Status report + + header_committed: BOOLEAN + -- Header committed? + do + Result := wgi_response.header_committed + end + + message_committed: BOOLEAN + -- Message committed? + do + Result := wgi_response.message_committed + end + + message_writable: BOOLEAN + -- Can message be written? + do + Result := wgi_response.message_writable + end + +--feature {WGI_RESPONSE_BUFFER} -- Core output operation + +-- write (s: READABLE_STRING_8) +-- -- Send the string `s' +-- -- this can be used for header and body +-- do +-- wgi_response.write (s) +-- end + +feature -- Status setting + + status_is_set: BOOLEAN + -- Is status set? + do + Result := wgi_response.status_is_set + end + + set_status_code (a_code: INTEGER) + -- Set response status code + -- Should be done before sending any data back to the client + require + status_not_set: not status_is_set + header_not_committed: not header_committed + do + wgi_response.set_status_code (a_code) + ensure + status_code_set: status_code = a_code + status_set: status_is_set + end + + status_code: INTEGER + -- Response status + do + Result := wgi_response.status_code + end + +feature -- Header output operation + + write_headers_string (a_headers: READABLE_STRING_8) + require + status_set: status_is_set + header_not_committed: not header_committed + do + wgi_response.write_headers_string (a_headers) + ensure + status_set: status_is_set + header_committed: header_committed + message_writable: message_writable + end + + write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]) + -- Send headers with status `a_status', and headers from `a_headers' + require + status_not_set: not status_is_set + header_not_committed: not header_committed + do + wgi_response.write_header (a_status_code, a_headers) + ensure + header_committed: header_committed + status_set: status_is_set + message_writable: message_writable + end + +feature -- Output operation + + write_string (s: READABLE_STRING_8) + -- Send the string `s' + require + message_writable: message_writable + do + wgi_response.write_string (s) + end + + write_substring (s: READABLE_STRING_8; a_begin_index, a_end_index: INTEGER) + -- Send the substring `s[a_begin_index:a_end_index]' + require + message_writable: message_writable + do + wgi_response.write_substring (s, a_begin_index, a_end_index) + end + + write_file_content (fn: READABLE_STRING_8) + -- Send the content of file `fn' + require + message_writable: message_writable + do + wgi_response.write_file_content (fn) + end + + flush + -- Flush if it makes sense + do + wgi_response.flush + end + +note + copyright: "2011-2011, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/server/wsf/wsf-safe.ecf b/library/server/wsf/wsf-safe.ecf new file mode 100644 index 00000000..5f420cf7 --- /dev/null +++ b/library/server/wsf/wsf-safe.ecf @@ -0,0 +1,20 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + + + + diff --git a/library/server/wsf/wsf.ecf b/library/server/wsf/wsf.ecf new file mode 100644 index 00000000..96f7f00b --- /dev/null +++ b/library/server/wsf/wsf.ecf @@ -0,0 +1,16 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + +