From 30a5e087ae21b102d6f9b05bd8150acba4bc574b Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 2 Oct 2020 15:02:06 +0200 Subject: [PATCH] Web form: - Improvement about web form manipulation (remove a field, set a text value to input fields by name, ...) - Improved web form html generation, especially for select and type checkbox - Updated the date input field interface with a new set_date_value . File response: - "application/force-download" is not a standard MIME content type, so use "application_octet_stream" instead as default. Standalone connector: - Added expected creation procedure for the service launcher. - Added new "secure_port" configuration variable, for SSL standalone service. This way, if `is_secure` is True, the server will use `secure_port` (overrides `port` value). Date: - Improved support for RFC 3339 (a profile of ISO 8601) Removed obsolete and warnings: - removed usage of FILE_NAME - updated code to avoid implicit conversion from STRING_32 to STRING_8 - avoid uneed conversion to STRING_8 (when possible) --- .../http_client/src/http_client_constants.e | 20 +-- .../http_client/src/http_client_request.e | 2 +- .../http_client/src/http_client_response.e | 16 ++- .../http_client/src/http_client_session.e | 9 +- .../libcurl/libcurl_http_client_session.e | 13 +- .../src/spec/net/net_http_client_request.e | 4 +- .../http_client/tests/test_http_client_i.e | 2 - .../http_client/tests/test_with_web_i.e | 2 +- .../parsers/http_accept_language_utilities.e | 2 +- .../http_accept_media_type_utilities.e | 2 +- .../src/results/http_accept_language.e | 6 +- .../test/common_accept_header_parser_test.e | 2 +- .../test/language_parser_test.e | 2 +- .../test/mime_parser_test.e | 2 +- .../network/protocol/http/src/http_cookie.e | 10 +- library/network/protocol/http/src/http_date.e | 127 +++++++++++++++++- .../protocol/http/src/http_format_constants.e | 6 +- .../network/protocol/http/src/http_header.e | 6 +- .../protocol/http/src/http_header_modifier.e | 10 +- .../protocol/http/src/http_media_type.e | 24 ++-- .../protocol/http/src/http_mime_types.e | 2 + .../protocol/http/src/http_parameter_table.e | 11 +- .../protocol/http/tests/http_date_test_set.e | 25 ++++ library/network/protocol/http/tests/tests.ecf | 1 + .../notification_external_mailer.e | 84 ++++++------ .../notification_email/notification_mailer.e | 6 +- .../notification_null_mailer.e | 4 +- .../notification_sendmail_mailer.e | 6 +- .../notification_storage_mailer.e | 4 +- .../smtp/notification_smtp_mailer.e | 6 +- .../storage/notification_email_file_storage.e | 4 +- .../storage/notification_email_storage.e | 4 +- library/security/jwt/README.md | 1 - library/security/jwt/src/jwt_claimset.e | 2 +- .../request/wgi_request_cgi_variables.e | 2 +- .../implementation/wgi_request_from_table.e | 8 +- .../scoop/httpd_connection_handler.e | 2 +- .../thread/httpd_connection_handler.e | 2 +- .../concurrency/thread/pool/pooled_thread.e | 4 +- .../concurrency/thread/pool/thread_pool.e | 4 +- .../wsf_standalone_service_launcher.e | 12 +- .../wsf_standalone_service_options.e | 9 ++ .../wsf/extension/filter/wsf_debug_filter.e | 6 +- .../extension/handler/cgi/wsf_cgi_handler.e | 9 +- .../wsf/extension/handler/wsf_debug_handler.e | 4 +- .../extension/handler/wsf_handler_helper.e | 9 +- .../wsf/extension/wsf_debug_information.e | 2 +- .../wsf/extension/wsf_request_utility.e | 9 +- .../wsf/extension/wsf_request_utility_proxy.e | 6 +- .../wsf_router_self_documentation_handler.e | 2 +- .../wsf_router_self_documentation_message.e | 10 +- .../router/filter/wsf_custom_header_filter.e | 4 +- .../wsf/router/misc/wsf_format_utility.e | 23 ++-- .../condition/wsf_with_condition_mapping_i.e | 4 +- .../helpers/wsf_routed_uri_template_helper.e | 2 +- .../wsf/router/wsf_file_system_handler.e | 6 +- .../wsf/router/wsf_http_protocol_version.e | 8 +- library/server/wsf/router/wsf_router.e | 4 +- .../server/wsf/router/wsf_routing_handler.e | 5 +- .../src/implementation/wsf_percent_encoder.e | 4 +- ...pplication_x_www_form_urlencoded_handler.e | 2 +- .../server/wsf/src/mime/wsf_mime_handler.e | 4 +- .../mime/wsf_multipart_form_data_handler.e | 4 +- .../server/wsf/src/request/value/wsf_any.e | 3 +- .../wsf/src/request/value/wsf_uploaded_file.e | 4 +- .../wsf/src/response/wsf_download_response.e | 2 +- .../wsf/src/response/wsf_file_response.e | 2 +- .../wsf_method_not_allowed_response.e | 9 +- .../wsf/src/response/wsf_page_response.e | 8 +- .../service/wsf_service_launcher_options.e | 4 +- library/server/wsf/src/wsf_request.e | 19 ++- library/server/wsf_html/wsf_html.ecf | 1 + library/text/encoder/src/base64.e | 14 +- library/text/encoder/src/json_encoder.e | 4 +- library/text/encoder/src/percent_encoder.e | 4 +- library/text/encoder/src/xml_encoder.e | 4 +- .../feed/src/support/feed_to_xhtml_visitor.e | 4 +- .../parser/uri_template/src/uri_template.e | 19 +-- .../utility/general/error/src/error_custom.e | 4 +- .../src/visitor/file_output_error_visitor.e | 2 +- 80 files changed, 444 insertions(+), 260 deletions(-) diff --git a/library/network/http_client/src/http_client_constants.e b/library/network/http_client/src/http_client_constants.e index c0a16c99..990f9da4 100644 --- a/library/network/http_client/src/http_client_constants.e +++ b/library/network/http_client/src/http_client_constants.e @@ -1,6 +1,4 @@ note - description: "Summary description for {HTTP_CLIENT_CONSTANTS}." - author: "" date: "$Date$" revision: "$Revision$" @@ -10,23 +8,19 @@ class feature -- Auth type auth_type_id (a_auth_type_string: READABLE_STRING_8): INTEGER - local - s: STRING_8 do - create s.make_from_string (a_auth_type_string) - s.to_lower - if s.same_string_general ("basic") then + if a_auth_type_string.is_case_insensitive_equal ("basic") then Result := Auth_type_basic - elseif s.same_string_general ("digest") then + elseif a_auth_type_string.is_case_insensitive_equal ("digest") then Result := Auth_type_digest - elseif s.same_string_general ("any") then + elseif a_auth_type_string.is_case_insensitive_equal ("any") then Result := Auth_type_any - elseif s.same_string_general ("anysafe") then + elseif a_auth_type_string.is_case_insensitive_equal ("anysafe") then Result := Auth_type_anysafe - elseif s.same_string_general ("none") then + elseif a_auth_type_string.is_case_insensitive_equal ("none") then Result := Auth_type_none end - end + end Auth_type_none: INTEGER = 0 Auth_type_basic: INTEGER = 1 @@ -35,7 +29,7 @@ feature -- Auth type Auth_type_anysafe: INTEGER = 4 note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/http_client_request.e b/library/network/http_client/src/http_client_request.e index e686e913..aac0eabc 100644 --- a/library/network/http_client/src/http_client_request.e +++ b/library/network/http_client/src/http_client_request.e @@ -108,7 +108,7 @@ feature {HTTP_CLIENT_SESSION} -- Execution feature -- Authentication - auth_type: STRING + auth_type: READABLE_STRING_8 -- Set the authentication type for the request. -- Types: "basic", "digest", "any" do diff --git a/library/network/http_client/src/http_client_response.e b/library/network/http_client/src/http_client_response.e index ed297e20..1bedd2a3 100644 --- a/library/network/http_client/src/http_client_response.e +++ b/library/network/http_client/src/http_client_response.e @@ -18,7 +18,7 @@ feature {NONE} -- Initialization do --| Default values status := 200 - url := a_url + create url.make_from_string (a_url) create {STRING_8} raw_header.make_empty end @@ -46,7 +46,7 @@ feature {HTTP_CLIENT_REQUEST} -- Status setting feature -- Access - url: STRING_8 + url: IMMUTABLE_STRING_8 -- URL associated with Current response status: INTEGER assign set_status @@ -163,7 +163,7 @@ feature -- Access end c := h.index_of (':', l_start) if c > 0 then - k := h.substring (l_start, c - 1) + k := h.substring (l_start, c - 1).to_string_8 k.right_adjust c := c + 1 from until c <= n and not h[c].is_space loop @@ -290,7 +290,7 @@ feature -- Change l_has_location: BOOLEAN l_content_length: INTEGER s: READABLE_STRING_8 - l_status_line,h: detachable STRING_8 + l_status_line,h: detachable READABLE_STRING_8 do from i := 1 @@ -363,6 +363,7 @@ feature -- Change -- Set http header `raw_header' to `h' local i: INTEGER + rs: READABLE_STRING_8 s: STRING_8 do raw_header := h @@ -372,8 +373,9 @@ feature -- Change --| Set status line, right away. i := h.index_of ('%N', 1) if i > 0 then - s := h.substring (1, i - 1) - if s.starts_with ("HTTP/") then + rs := h.substring (1, i - 1) + if rs.starts_with ("HTTP/") then + s := rs.to_string_8 s.right_adjust set_status_line (s) end @@ -405,7 +407,7 @@ feature {NONE} -- Implementation -- Internal cached value for the headers ;note - copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/http_client_session.e b/library/network/http_client/src/http_client_session.e index 53e3af2c..cc399a85 100644 --- a/library/network/http_client/src/http_client_session.e +++ b/library/network/http_client/src/http_client_session.e @@ -63,10 +63,11 @@ feature -- Access do if is_absolute_url (a_path) then -- Is Absolute url - Result := a_path + Result := a_path.to_string_8 else - Result := base_url + a_path - end + create Result.make_from_string (base_url) + Result.append (a_path) + end if ctx /= Void then ctx.append_query_parameters_to_url (Result) end @@ -287,7 +288,7 @@ feature -- Access feature -- Authentication - auth_type: STRING + auth_type: READABLE_STRING_8 -- Set the authentication type for the request. -- Types: "basic", "digest", "any" diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e index a17f2204..2f282355 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e @@ -31,7 +31,7 @@ feature -- Status report is_available: BOOLEAN -- Is interface usable? do - Result := curl.is_dynamic_library_exists + Result := curl.is_api_available end feature -- Custom @@ -139,12 +139,17 @@ feature {NONE} -- Implementation l_data := ctx.upload_data if l_data /= Void and a_method.is_case_insensitive_equal_general ("PUT") then --| Quick and dirty hack using real file, for PUT uploaded data - --| FIXME [2012-05-23]: better use libcurl for that purpose + --| FIXME [2012-05-23]: find better solution with libcurl for that need if ctx.has_upload_filename then check put_conflict_file_and_data: False end end - create f.make_open_write (create {FILE_NAME}.make_temporary_name) + + if attached {EXECUTION_ENVIRONMENT}.temporary_directory_path as tmp then + create f.make_open_temporary_with_prefix (tmp.extended ("tmp-libcurl-").name) + else + create f.make_open_temporary_with_prefix ("tmp-libcurl-") + end f.put_string (l_data) f.close check ctx /= Void then @@ -176,7 +181,7 @@ feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation ;note - copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/spec/net/net_http_client_request.e b/library/network/http_client/src/spec/net/net_http_client_request.e index 63cca7e9..a1c6d4bf 100644 --- a/library/network/http_client/src/spec/net/net_http_client_request.e +++ b/library/network/http_client/src/spec/net/net_http_client_request.e @@ -125,7 +125,7 @@ feature -- Access if attached l_uri.host as h then l_host := h else - create l_url.make (url) + create l_url.make (url.to_string_8) l_host := l_url.host end @@ -887,7 +887,7 @@ feature {NONE} -- Helpers invariant note - copyright: "2011-2018, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/tests/test_http_client_i.e b/library/network/http_client/tests/test_http_client_i.e index 621ec4d4..f06bf72c 100644 --- a/library/network/http_client/tests/test_http_client_i.e +++ b/library/network/http_client/tests/test_http_client_i.e @@ -112,7 +112,6 @@ feature -- Test routines -- New test routine local sess: like new_session - h: STRING_8 config: HTTP_CLIENT_SECURE_CONFIG do --| Set secure configuration @@ -160,7 +159,6 @@ feature -- Test routines test_abs_url local sess: like new_session - h: STRING_8 l_url: STRING do sess := new_session ("https://www.eiffel.org") diff --git a/library/network/http_client/tests/test_with_web_i.e b/library/network/http_client/tests/test_with_web_i.e index e1539ea4..127326d7 100644 --- a/library/network/http_client/tests/test_with_web_i.e +++ b/library/network/http_client/tests/test_with_web_i.e @@ -61,7 +61,7 @@ feature -- Requestbin j := l_content.index_of ('}', i + 1) end if j > 0 then - Result := l_content.substring (i + 7, j - 1) + Result := l_content.substring (i + 7, j - 1).to_string_8 Result.adjust if Result.starts_with ("%"") then Result.remove_head (1) diff --git a/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e index 6d69f6f8..4c342d4f 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_language_utilities.e @@ -168,7 +168,7 @@ feature {NONE} -- Implementation l_target_type: READABLE_STRING_8 l_range: HTTP_ACCEPT_LANGUAGE l_param_matches: INTEGER - l_element: detachable READABLE_STRING_8 + l_element: detachable READABLE_STRING_GENERAL l_fitness: INTEGER do l_best_fitness := -1 diff --git a/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e index c57e060a..6983553b 100644 --- a/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e +++ b/library/network/protocol/content_negotiation/src/parsers/http_accept_media_type_utilities.e @@ -190,7 +190,7 @@ feature {NONE} -- Implementation target: HTTP_MEDIA_TYPE range: HTTP_MEDIA_TYPE param_matches: INTEGER - element: detachable READABLE_STRING_8 + element: detachable READABLE_STRING_GENERAL l_fitness: INTEGER do best_fitness := -1 diff --git a/library/network/protocol/content_negotiation/src/results/http_accept_language.e b/library/network/protocol/content_negotiation/src/results/http_accept_language.e index a58137c5..ee879a16 100644 --- a/library/network/protocol/content_negotiation/src/results/http_accept_language.e +++ b/library/network/protocol/content_negotiation/src/results/http_accept_language.e @@ -172,7 +172,7 @@ feature -- Element change feature -- Parameters: Access - parameter (a_key: READABLE_STRING_8): detachable READABLE_STRING_8 + parameter (a_key: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- Parameter associated with `a_key', if present -- otherwise default value of type `STRING' do @@ -186,7 +186,7 @@ feature -- Parameters: Access feature -- Parameters: Status report - has_parameter (a_key: READABLE_STRING_8): BOOLEAN + has_parameter (a_key: READABLE_STRING_GENERAL): BOOLEAN -- Is there an parameter in the parameters table with key `a_key'? do if attached parameters as l_params then @@ -196,7 +196,7 @@ feature -- Parameters: Status report feature -- Parameters: Change - put_parameter (a_value: READABLE_STRING_8; a_key: READABLE_STRING_8) + put_parameter (a_value: READABLE_STRING_8; a_key: READABLE_STRING_GENERAL) -- Insert `a_value' with `a_key' if there is no other item -- associated with the same key. If present, replace -- the old value with `a_value' diff --git a/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e b/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e index 1c736576..3cb292a4 100644 --- a/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e +++ b/library/network/protocol/content_negotiation/test/common_accept_header_parser_test.e @@ -35,7 +35,7 @@ feature -- Helpers across l_parameters as ic loop - Result.append ("'" + ic.key + "':'" + ic.item + "',"); + Result.append ("'" + {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (ic.key) + "':'" + ic.item + "',"); end end Result.append ("})") diff --git a/library/network/protocol/content_negotiation/test/language_parser_test.e b/library/network/protocol/content_negotiation/test/language_parser_test.e index fe937a20..f816589a 100644 --- a/library/network/protocol/content_negotiation/test/language_parser_test.e +++ b/library/network/protocol/content_negotiation/test/language_parser_test.e @@ -38,7 +38,7 @@ feature -- Helpers across l_params as ic loop - Result.append ("'" + ic.key + "':'"+ ic.item + "',"); + Result.append ("'" + {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (ic.key) + "':'"+ ic.item + "',"); end end Result.append ("})") diff --git a/library/network/protocol/content_negotiation/test/mime_parser_test.e b/library/network/protocol/content_negotiation/test/mime_parser_test.e index 2a861868..dd880758 100644 --- a/library/network/protocol/content_negotiation/test/mime_parser_test.e +++ b/library/network/protocol/content_negotiation/test/mime_parser_test.e @@ -41,7 +41,7 @@ feature -- Helper across l_params as ic loop - Result.append ("'" + ic.key + "':'" + ic.item + "',"); + Result.append ("'" + {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (ic.key) + "':'" + ic.item + "',"); end end Result.append ("})") diff --git a/library/network/protocol/http/src/http_cookie.e b/library/network/protocol/http/src/http_cookie.e index 72527755..1900b64f 100644 --- a/library/network/protocol/http/src/http_cookie.e +++ b/library/network/protocol/http/src/http_cookie.e @@ -47,21 +47,21 @@ feature {NONE} -- Initialization feature -- Access - name: STRING_8 + name: READABLE_STRING_8 -- name of the cookie. - value: STRING_8 + value: READABLE_STRING_8 -- value of the cookie. - expiration: detachable STRING_8 + expiration: detachable READABLE_STRING_8 -- Value of the Expires attribute. - path: detachable STRING_8 + path: detachable READABLE_STRING_8 -- Value of the Path attribute. -- Path to which the cookie applies. --| The path "/", specify a cookie that apply to all URLs in your site. - domain: detachable STRING_8 + domain: detachable READABLE_STRING_8 -- Value of the Domain attribute. -- Domain to which the cookies apply. diff --git a/library/network/protocol/http/src/http_date.e b/library/network/protocol/http/src/http_date.e index 7930766e..643e8cc3 100644 --- a/library/network/protocol/http/src/http_date.e +++ b/library/network/protocol/http/src/http_date.e @@ -42,6 +42,7 @@ create make_now_utc, make_from_timestamp, make_from_string, + make_from_rfc3339_string, make_from_date_time feature {NONE} -- Initialization @@ -65,6 +66,18 @@ feature {NONE} -- Initialization date_time := dt elseif attached ansi_c_string_to_date_time (s) as dt then date_time := dt + elseif attached rfc3339_string_to_date_time (s) as dt then + date_time := dt + else + has_error := True + date_time := epoch + end + end + + make_from_rfc3339_string (s: READABLE_STRING_GENERAL) + do + if attached rfc3339_string_to_date_time (s) as dt then + date_time := dt else has_error := True date_time := epoch @@ -153,10 +166,13 @@ feature -- Conversion to string append_date_time_to_rfc850_string (date_time, Result) end + iso8601_string, rfc3339_string: STRING -- String representation following RFC 3339. -- format: [yyyy-mm-ddThh:mi:ssZ] -- https://www.rfc-editor.org/rfc/rfc3339.txt + -- note: RFC 3339 is a profile of ISO 8601. + -- https://en.wikipedia.org/wiki/ISO_8601 do create Result.make (25) append_date_time_to_rfc3339_string (date_time, Result) @@ -241,6 +257,7 @@ feature -- Conversion into string s.append (" GMT") -- SPace + GMT end + append_date_time_to_iso8601_string, append_date_time_to_rfc3339_string (dt: DATE_TIME; s: STRING_GENERAL) -- Append `dt' as [yyyy-mm-ddThh:mi:ssZ] format to `s'. do @@ -316,7 +333,7 @@ feature -- Helper routines. create fd.make (2, 2) fd.show_trailing_zeros fd.show_zero - r64 := t.fine_second + r64 := t.second + t.fractional_second * 0.01 f := fd.formatted (r64) if f.ends_with_general (".00") then append_2_digits_integer_to (t.second, s) -- ss @@ -670,7 +687,7 @@ feature {NONE} -- Implementation end ansi_c_string_to_date_time (s: READABLE_STRING_GENERAL): detachable DATE_TIME - -- String representation of `dt' using the RFC 1123 + -- ANSI C date from `s` string representation using the RFC 1123 -- asctime-date = wkday SP date3 SP time SP 4DIGIT -- date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) -- ; month day (e.g., Jun 2) @@ -919,10 +936,114 @@ feature {NONE} -- Implementation end end + rfc3339_string_to_date_time (s: READABLE_STRING_GENERAL): detachable DATE_TIME + --| 1985-04-12T23:20:50.52Z + --| 1996-12-19T16:39:57-08:00 = 1996-12-20T00:39:57Z + --| + note + EIS: "name=RFC3339", "protocol=URI", "src=https://tools.ietf.org/html/rfc3339" + local + y,mo,d,h,mi,sec, frac_sec: INTEGER + l_off_h, l_off_mi: INTEGER + tmp: READABLE_STRING_GENERAL + i, j, k, pos: INTEGER + err: BOOLEAN + do + if s /= Void then + pos := s.index_of ('T', 1) + if pos > 0 then + i := 1 + j := s.index_of ('-', i) + if j > i and j < pos then + y := s.substring (i, j - 1).to_integer + i := j + 1 + j := s.index_of ('-', i) + if j > i and j < pos then + mo := s.substring (i, j - 1).to_integer + d := s.substring (j + 1, pos - 1).to_integer + else + err := True + end + else + err := True + end + i := pos + 1 + j := s.index_of (':', i) + if j > i then + h := s.substring (i, j - 1).to_integer + i := j + 1 + j := s.index_of (':', i) + if j > i then + mi := s.substring (i, j - 1).to_integer + from + k := j + 1 + until + k > s.count + or s[k].is_alpha + or s[k] = '+' + or s[k] = '-' + loop + k := k + 1 + end + tmp := s.substring (j + 1, k - 1) + j := tmp.index_of ('.', 1) + if j > 0 then + sec := tmp.head (j - 1).to_integer + frac_sec := tmp.substring (j + 1, tmp.count).to_integer + else + sec := tmp.to_integer + end + if k <= s.count then + if s[k] = '+' then + tmp := s.substring (k + 1, s.count) + j := tmp.index_of (':', 1) + if j > 0 then + l_off_h := - tmp.head (j - 1).to_integer + l_off_mi := - tmp.substring (j + 1, tmp.count).to_integer + else + l_off_h := - tmp.to_integer + end + elseif s[k] = '-' then + tmp := s.substring (k + 1, s.count) + j := tmp.index_of (':', 1) + if j > 0 then + l_off_h := + tmp.head (j - 1).to_integer + l_off_mi := + tmp.substring (j + 1, tmp.count).to_integer + else + l_off_h := + tmp.to_integer + end + elseif s[k] = 'Z' then + -- Done + else + end + end + else + err := True + end + else + err := True + end + if not err then + create Result.make (y, mo, d, h, mi, sec) + if frac_sec /= 0 then + Result.set_fractionals (frac_sec) + Result.time.set_fractionals (frac_sec) + end + if l_off_h /= 0 then + Result.hour_add (l_off_h) + end + if l_off_mi /= 0 then + Result.minute_add (l_off_mi) + end + end + end + end + end + invariant note - copyright: "2011-2019, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/protocol/http/src/http_format_constants.e b/library/network/protocol/http/src/http_format_constants.e index 67b6312c..bec64ec3 100644 --- a/library/network/protocol/http/src/http_format_constants.e +++ b/library/network/protocol/http/src/http_format_constants.e @@ -40,9 +40,9 @@ feature -- Query format_id (a_id: READABLE_STRING_GENERAL): INTEGER local - s: STRING + s: READABLE_STRING_GENERAL do - s := a_id.as_string_8.as_lower + s := a_id.as_lower if s.same_string (json_name) then Result := json elseif s.same_string (xml_name) then @@ -74,7 +74,7 @@ feature -- Query end note - copyright: "2011-2011, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/protocol/http/src/http_header.e b/library/network/protocol/http/src/http_header.e index 165f2877..b422e280 100644 --- a/library/network/protocol/http/src/http_header.e +++ b/library/network/protocol/http/src/http_header.e @@ -175,7 +175,7 @@ feature -- Header: adding across lines as c loop - line := c.item + line := c.item.to_string_8 if not line.is_empty then if line [line.count] = '%R' then line.remove_tail (1) @@ -223,7 +223,7 @@ feature -- Header: merging across lines as c loop - line := c.item + line := c.item.to_string_8 if not line.is_empty then if line [line.count] = '%R' then line.remove_tail (1) @@ -416,7 +416,7 @@ feature {NONE} -- Implementation: Header queries end note - copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/protocol/http/src/http_header_modifier.e b/library/network/protocol/http/src/http_header_modifier.e index e7ca06c8..645d6daf 100644 --- a/library/network/protocol/http/src/http_header_modifier.e +++ b/library/network/protocol/http/src/http_header_modifier.e @@ -106,7 +106,7 @@ feature -- Access loop l_line := ic.item if has_same_header_name (l_line, a_header_name) then - res := l_line.substring (n + 2, l_line.count) + res := l_line.substring (n + 2, l_line.count).to_string_8 res.left_adjust res.right_adjust Result := res @@ -271,25 +271,25 @@ feature -- Content related header put_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8) -- Put content type `a_content_type' with `a_charset' as "charset" parameter. do - put_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>) + put_content_type_with_parameters (a_content_type, {ARRAY [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]} <<["charset", a_charset]>>) end add_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8) -- Same as `put_content_type_with_charset', but allow multiple definition of "Content-Type". do - add_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>) + add_content_type_with_parameters (a_content_type, {ARRAY [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]} <<["charset", a_charset]>>) end put_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8) -- Put content type `a_content_type' with `a_name' as "name" parameter. do - put_content_type_with_parameters (a_content_type, <<["name", a_name]>>) + put_content_type_with_parameters (a_content_type, {ARRAY [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]} <<["name", a_name]>>) end add_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8) -- same as `put_content_type_with_name', but allow multiple definition of "Content-Type" do - add_content_type_with_parameters (a_content_type, <<["name", a_name]>>) + add_content_type_with_parameters (a_content_type, {ARRAY [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]} <<["name", a_name]>>) end put_content_length (a_length: INTEGER) diff --git a/library/network/protocol/http/src/http_media_type.e b/library/network/protocol/http/src/http_media_type.e index d2d9614e..84e08307 100644 --- a/library/network/protocol/http/src/http_media_type.e +++ b/library/network/protocol/http/src/http_media_type.e @@ -77,10 +77,10 @@ feature {NONE} -- Initialization -- Look for semi colon as parameter separation p := s.index_of (';', i) if p > 0 then - t := s.substring (i, p - 1) + t := s.substring (i, p - 1).to_string_8 create parameters.make_from_substring (s, p + 1, s.count) else - t := s.substring (i, n) + t := s.substring (i, n).to_string_8 end -- Remove eventual trailing space t.right_adjust @@ -124,7 +124,7 @@ feature -- Access subtype: READABLE_STRING_8 -- Sub type - has_parameter (a_name: READABLE_STRING_8): BOOLEAN + has_parameter (a_name: READABLE_STRING_GENERAL): BOOLEAN -- Has Current a parameter? do if attached parameters as plst then @@ -132,7 +132,7 @@ feature -- Access end end - parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 + parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8 -- Value for eventual parameter named `a_name'. do if attached parameters as plst then @@ -159,7 +159,7 @@ feature -- Conversion loop res.append_character (';') res.append_character (' ') - res.append (p.key) + res.append ({UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (p.key)) res.append_character ('=') res.append_character ('%"') res.append (p.item) @@ -272,13 +272,19 @@ feature -- Status report debug_output: STRING -- String that should be displayed in debugger to represent `Current'. do - if type /= Void and subtype /= Void then - Result := type + "/" + subtype + if attached type as l_type and attached subtype as l_subtype then + create Result.make_from_string (l_type) + Result.append_character ('/') + Result.append (l_subtype) if attached parameters as plst then across plst as p loop - Result.append ("; " + p.key + "=" + "%"" + p.item + "%"") + Result.append ("; ") + Result.append ({UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (p.key)) + Result.append ("=%"") + Result.append (p.item) + Result.append_character ('%"') end end else @@ -290,7 +296,7 @@ invariant type_and_subtype_not_empty: not has_error implies not type.is_empty and not subtype.is_empty note - copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/protocol/http/src/http_mime_types.e b/library/network/protocol/http/src/http_mime_types.e index 37d8a924..96d49730 100644 --- a/library/network/protocol/http/src/http_mime_types.e +++ b/library/network/protocol/http/src/http_mime_types.e @@ -20,6 +20,8 @@ feature -- Content type : application -- atom application content-type header application_force_download: STRING = "application/force-download" + -- Warning: this is not a standard MIME content type. + -- Prefer application_octet_stream as default. application_javascript: STRING = "application/javascript" -- JavaScript application content-type header diff --git a/library/network/protocol/http/src/http_parameter_table.e b/library/network/protocol/http/src/http_parameter_table.e index 21d8995c..1dc0e292 100644 --- a/library/network/protocol/http/src/http_parameter_table.e +++ b/library/network/protocol/http/src/http_parameter_table.e @@ -9,7 +9,7 @@ class HTTP_PARAMETER_TABLE inherit - HASH_TABLE [READABLE_STRING_8, STRING_8] + STRING_TABLE [READABLE_STRING_8] redefine empty_duplicate end @@ -58,7 +58,8 @@ feature {NONE} -- Implementation -- and put in `out_end_index' the index after found parameter. local n: INTEGER - pn,pv: STRING_8 + pn: READABLE_STRING_8 + pv: STRING_8 i: INTEGER p, q: INTEGER err: BOOLEAN @@ -86,7 +87,7 @@ feature {NONE} -- Implementation if s[p+1] = '%"' then q := s.index_of ('%"', p + 2) if q > 0 then - pv := s.substring (p + 2, q - 1) + pv := s.substring (p + 2, q - 1).to_string_8 from i := q + 1 until @@ -108,7 +109,7 @@ feature {NONE} -- Implementation if q = 0 then q := n + 1 end - pv := s.substring (p + 1, q - 1) + pv := s.substring (p + 1, q - 1).to_string_8 out_end_index.replace (q + 1) end pv.right_adjust @@ -138,7 +139,7 @@ feature {NONE} -- Duplication end note - copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others" + copyright: "2011-2020, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/protocol/http/tests/http_date_test_set.e b/library/network/protocol/http/tests/http_date_test_set.e index f81df5c7..22638ed5 100644 --- a/library/network/protocol/http/tests/http_date_test_set.e +++ b/library/network/protocol/http/tests/http_date_test_set.e @@ -74,4 +74,29 @@ feature -- Test routines end + test_http_date_rfc3339 + local + s: STRING + d: HTTP_DATE + dt: DATE_TIME + do + create dt.make_now_utc + create dt.make (1985, 04, 12, 23, 20, 50) + dt.set_fractionals (52) + dt.time.set_fractionals (52) + + create d.make_from_date_time (dt) + s := "1985-04-12T23:20:50.52Z" + assert ("RFC 3339 to string", d.rfc3339_string.same_string (s)) + + create d.make_from_rfc3339_string (s) + assert ("RFC 3339 from string", not d.has_error and then d.date_time.is_equal (dt)) + + create d.make_from_rfc3339_string ("1996-12-19T16:39:57-08:00") + assert ("-8hours", d.rfc3339_string.same_string ("1996-12-20T00:39:57Z")) + + create d.make_from_rfc3339_string ("1937-01-01T12:00:27.87+00:20") + assert ("-8hours", d.rfc3339_string.same_string ("1937-01-01T11:40:27.87Z")) + end + end diff --git a/library/network/protocol/http/tests/tests.ecf b/library/network/protocol/http/tests/tests.ecf index 9d9b702d..fe94e2cf 100644 --- a/library/network/protocol/http/tests/tests.ecf +++ b/library/network/protocol/http/tests/tests.ecf @@ -14,6 +14,7 @@ +