From f74ac66569710c03bb03fbefab2bc49f6a6ad9ff Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 12 Jul 2011 11:53:00 +0200 Subject: [PATCH] First integration of the new GW_ design more centralized on connector, and does not require specific feature on GW_APPLICATION depending on the connector. So this is really more flexible this way, and much easier to write application supporting CGI, FCGI, Nino and so on .. as demonstrated in hello_world This is a first version, more will come later, mainly migrating from Eiffel Web Reloaded to this Eiffel Web Framework project. --- ext/server/nino | 2 +- library/error/error-safe.ecf | 16 + library/error/error.ecf | 16 + library/error/license.lic | 1 + library/error/src/error.e | 80 ++ library/error/src/error_custom.e | 57 ++ library/error/src/error_group.e | 75 ++ library/error/src/error_handler.e | 92 ++ library/error/src/visitor/error_iterator.e | 49 ++ .../error/src/visitor/error_null_visitor.e | 38 + library/error/src/visitor/error_visitor.e | 35 + .../src/visitor/file_output_error_visitor.e | 53 ++ .../error/src/visitor/output_error_visitor.e | 93 ++ .../src/visitor/text_output_error_visitor.e | 53 ++ library/protocol/http/http-safe.ecf | 17 + library/protocol/http/http.ecf | 18 + library/protocol/http/src/http_constants.e | 97 +++ .../http/src/http_date_time_utilities.e | 71 ++ library/protocol/http/src/http_status_code.e | 106 +++ .../http/src/http_status_code_messages.e | 160 ++++ library/{ => server}/ewsgi/COPYRIGHT | 0 .../server/ewsgi/connectors/cgi/cgi-safe.ecf | 16 + library/server/ewsgi/connectors/cgi/cgi.ecf | 16 + .../server/ewsgi/connectors/cgi/license.lic | 1 + .../connectors/cgi/src/gw_cgi_connector.e | 36 + .../connectors/cgi/src/gw_cgi_input_stream.e | 39 + .../connectors/cgi/src/gw_cgi_output_stream.e | 39 + .../ewsgi/connectors/libfcgi/libfcgi-safe.ecf | 17 + .../ewsgi/connectors/libfcgi/libfcgi.ecf | 17 + .../ewsgi/connectors/libfcgi/license.lic | 1 + .../libfcgi/src/gw_libfcgi_connector.e | 81 ++ .../libfcgi/src/gw_libfcgi_input_stream.e | 66 ++ .../libfcgi/src/gw_libfcgi_output_stream.e | 57 ++ .../server/ewsgi/connectors/nino/license.lic | 1 + .../ewsgi/connectors/nino/nino-safe.ecf | 17 + library/server/ewsgi/connectors/nino/nino.ecf | 17 + .../connectors/nino/src/gw_nino_connector.e | 93 ++ .../connectors/nino/src/gw_nino_handler.e | 156 ++++ .../nino/src/gw_nino_input_stream.e | 61 ++ .../nino/src/gw_nino_output_stream.e | 60 ++ .../{ => server}/ewsgi/doc/cgi_spec_1.0.txt | 0 .../{ => server}/ewsgi/doc/cgi_spec_1.2.txt | 0 .../ewsgi.ecf => server/ewsgi/ewsgi-safe.ecf} | 8 +- library/server/ewsgi/ewsgi.ecf | 18 + .../ewsgi/examples/hello_world/hello-safe.ecf | 19 + .../examples/hello_world/src/hello_world.e | 58 ++ library/{ => server}/ewsgi/license.lic | 0 .../ewsgi/src/context}/gw_environment.e | 149 ++-- .../src/context/gw_environment_variables.e | 292 +++++++ .../src/context}/gw_execution_variables.e | 23 +- .../ewsgi/src/context}/gw_request_context.e | 51 +- .../ewsgi/src/context}/gw_request_variables.e | 37 +- .../ewsgi/src/context}/gw_variables.e | 18 + .../{ => server}/ewsgi/src/gw_application.e | 1 + library/server/ewsgi/src/gw_connector.e | 44 + library/{ => server}/ewsgi/src/gw_cookie.e | 0 .../ewsgi/src/gw_environment_names.e | 0 library/server/ewsgi/src/gw_error.e | 66 ++ .../src/implementation/gw_application_imp.e | 50 ++ .../implementation/gw_request_context_imp.e | 818 ++++++++++++++++++ .../ewsgi/src/stream}/gw_input_stream.e | 0 .../ewsgi/src/stream}/gw_output_stream.e | 0 library/server/libfcgi/README.txt | 7 + .../libfcgi/doc/Configuration_examples.txt | 50 ++ library/server/libfcgi/fcgi.ecf | 52 ++ .../libfcgi/implementation/fake/fcgi_imp.e | 104 +++ .../libfcgi/implementation/linux/fcgi_c_api.e | 97 +++ .../libfcgi/implementation/linux/fcgi_imp.e | 183 ++++ .../implementation/windows/fcgi_c_api.e | 136 +++ .../libfcgi/implementation/windows/fcgi_imp.e | 267 ++++++ library/server/libfcgi/interface/fcgi.e | 26 + library/server/libfcgi/interface/fcgi_i.e | 236 +++++ library/server/libfcgi/libfcgi-safe.ecf | 52 ++ library/server/libfcgi/libfcgi.ecf | 52 ++ library/server/libfcgi/license.lic | 1 + .../libfcgi/spec/include/libfcgi/fastcgi.h | 136 +++ .../spec/include/libfcgi/fcgi_config.h | 39 + .../spec/include/libfcgi/fcgi_config_x86.h | 39 + .../libfcgi/spec/include/libfcgi/fcgi_stdio.h | 246 ++++++ .../libfcgi/spec/include/libfcgi/fcgiapp.h | 622 +++++++++++++ .../libfcgi/spec/include/libfcgi/fcgimisc.h | 38 + .../libfcgi/spec/include/libfcgi/fcgio.h | 151 ++++ .../libfcgi/spec/include/libfcgi/fcgios.h | 130 +++ .../libfcgi/spec/lib/win64/msc/libfcgi.dll | Bin 0 -> 51200 bytes .../libfcgi/spec/lib/win64/msc/libfcgi.lib | Bin 0 -> 27710 bytes .../libfcgi/spec/lib/windows/msc/libfcgi.dll | Bin 0 -> 42496 bytes .../libfcgi/spec/lib/windows/msc/libfcgi.lib | Bin 0 -> 27920 bytes library/server/libfcgi/tests/apache2.conf | 64 ++ .../server/libfcgi/tests/application_root.e | 80 ++ library/server/libfcgi/tests/eiffelweb.ecf | 16 + library/text/encoder/encoder-safe.ecf | 35 + library/text/encoder/encoder.ecf | 35 + library/text/encoder/license.lic | 1 + library/text/encoder/src/base64.e | 218 +++++ library/text/encoder/src/encoder.e | 73 ++ library/text/encoder/src/html_encoder.e | 267 ++++++ library/text/encoder/src/url_encoder.e | 321 +++++++ library/text/encoder/src/xml_encoder.e | 267 ++++++ library/text/encoder/tests/test_base64.e | 49 ++ library/text/encoder/tests/test_url_encoder.e | 49 ++ library/text/encoder/tests/text_xml_encoder.e | 47 + 101 files changed, 7651 insertions(+), 107 deletions(-) create mode 100644 library/error/error-safe.ecf create mode 100644 library/error/error.ecf create mode 100644 library/error/license.lic create mode 100644 library/error/src/error.e create mode 100644 library/error/src/error_custom.e create mode 100644 library/error/src/error_group.e create mode 100644 library/error/src/error_handler.e create mode 100644 library/error/src/visitor/error_iterator.e create mode 100644 library/error/src/visitor/error_null_visitor.e create mode 100644 library/error/src/visitor/error_visitor.e create mode 100644 library/error/src/visitor/file_output_error_visitor.e create mode 100644 library/error/src/visitor/output_error_visitor.e create mode 100644 library/error/src/visitor/text_output_error_visitor.e create mode 100644 library/protocol/http/http-safe.ecf create mode 100644 library/protocol/http/http.ecf create mode 100644 library/protocol/http/src/http_constants.e create mode 100644 library/protocol/http/src/http_date_time_utilities.e create mode 100644 library/protocol/http/src/http_status_code.e create mode 100644 library/protocol/http/src/http_status_code_messages.e rename library/{ => server}/ewsgi/COPYRIGHT (100%) create mode 100644 library/server/ewsgi/connectors/cgi/cgi-safe.ecf create mode 100644 library/server/ewsgi/connectors/cgi/cgi.ecf create mode 100644 library/server/ewsgi/connectors/cgi/license.lic create mode 100644 library/server/ewsgi/connectors/cgi/src/gw_cgi_connector.e create mode 100644 library/server/ewsgi/connectors/cgi/src/gw_cgi_input_stream.e create mode 100644 library/server/ewsgi/connectors/cgi/src/gw_cgi_output_stream.e create mode 100644 library/server/ewsgi/connectors/libfcgi/libfcgi-safe.ecf create mode 100644 library/server/ewsgi/connectors/libfcgi/libfcgi.ecf create mode 100644 library/server/ewsgi/connectors/libfcgi/license.lic create mode 100644 library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_connector.e create mode 100644 library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_input_stream.e create mode 100644 library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_output_stream.e create mode 100644 library/server/ewsgi/connectors/nino/license.lic create mode 100644 library/server/ewsgi/connectors/nino/nino-safe.ecf create mode 100644 library/server/ewsgi/connectors/nino/nino.ecf create mode 100644 library/server/ewsgi/connectors/nino/src/gw_nino_connector.e create mode 100644 library/server/ewsgi/connectors/nino/src/gw_nino_handler.e create mode 100644 library/server/ewsgi/connectors/nino/src/gw_nino_input_stream.e create mode 100644 library/server/ewsgi/connectors/nino/src/gw_nino_output_stream.e rename library/{ => server}/ewsgi/doc/cgi_spec_1.0.txt (100%) rename library/{ => server}/ewsgi/doc/cgi_spec_1.2.txt (100%) rename library/{ewsgi/ewsgi.ecf => server/ewsgi/ewsgi-safe.ecf} (81%) create mode 100644 library/server/ewsgi/ewsgi.ecf create mode 100644 library/server/ewsgi/examples/hello_world/hello-safe.ecf create mode 100644 library/server/ewsgi/examples/hello_world/src/hello_world.e rename library/{ => server}/ewsgi/license.lic (100%) rename library/{ewsgi/src => server/ewsgi/src/context}/gw_environment.e (95%) create mode 100644 library/server/ewsgi/src/context/gw_environment_variables.e rename library/{ewsgi/src => server/ewsgi/src/context}/gw_execution_variables.e (70%) rename library/{ewsgi/src => server/ewsgi/src/context}/gw_request_context.e (85%) rename library/{ewsgi/src => server/ewsgi/src/context}/gw_request_variables.e (82%) rename library/{ewsgi/src => server/ewsgi/src/context}/gw_variables.e (75%) rename library/{ => server}/ewsgi/src/gw_application.e (91%) create mode 100644 library/server/ewsgi/src/gw_connector.e rename library/{ => server}/ewsgi/src/gw_cookie.e (100%) rename library/{ => server}/ewsgi/src/gw_environment_names.e (100%) create mode 100644 library/server/ewsgi/src/gw_error.e create mode 100644 library/server/ewsgi/src/implementation/gw_application_imp.e create mode 100644 library/server/ewsgi/src/implementation/gw_request_context_imp.e rename library/{ewsgi/src => server/ewsgi/src/stream}/gw_input_stream.e (100%) rename library/{ewsgi/src => server/ewsgi/src/stream}/gw_output_stream.e (100%) create mode 100644 library/server/libfcgi/README.txt create mode 100644 library/server/libfcgi/doc/Configuration_examples.txt create mode 100644 library/server/libfcgi/fcgi.ecf create mode 100644 library/server/libfcgi/implementation/fake/fcgi_imp.e create mode 100644 library/server/libfcgi/implementation/linux/fcgi_c_api.e create mode 100644 library/server/libfcgi/implementation/linux/fcgi_imp.e create mode 100644 library/server/libfcgi/implementation/windows/fcgi_c_api.e create mode 100644 library/server/libfcgi/implementation/windows/fcgi_imp.e create mode 100644 library/server/libfcgi/interface/fcgi.e create mode 100644 library/server/libfcgi/interface/fcgi_i.e create mode 100644 library/server/libfcgi/libfcgi-safe.ecf create mode 100644 library/server/libfcgi/libfcgi.ecf create mode 100644 library/server/libfcgi/license.lic create mode 100644 library/server/libfcgi/spec/include/libfcgi/fastcgi.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgi_config.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgi_config_x86.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgi_stdio.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgiapp.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgimisc.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgio.h create mode 100644 library/server/libfcgi/spec/include/libfcgi/fcgios.h create mode 100644 library/server/libfcgi/spec/lib/win64/msc/libfcgi.dll create mode 100644 library/server/libfcgi/spec/lib/win64/msc/libfcgi.lib create mode 100644 library/server/libfcgi/spec/lib/windows/msc/libfcgi.dll create mode 100644 library/server/libfcgi/spec/lib/windows/msc/libfcgi.lib create mode 100644 library/server/libfcgi/tests/apache2.conf create mode 100644 library/server/libfcgi/tests/application_root.e create mode 100644 library/server/libfcgi/tests/eiffelweb.ecf create mode 100644 library/text/encoder/encoder-safe.ecf create mode 100644 library/text/encoder/encoder.ecf create mode 100644 library/text/encoder/license.lic create mode 100644 library/text/encoder/src/base64.e create mode 100644 library/text/encoder/src/encoder.e create mode 100644 library/text/encoder/src/html_encoder.e create mode 100644 library/text/encoder/src/url_encoder.e create mode 100644 library/text/encoder/src/xml_encoder.e create mode 100644 library/text/encoder/tests/test_base64.e create mode 100644 library/text/encoder/tests/test_url_encoder.e create mode 100644 library/text/encoder/tests/text_xml_encoder.e diff --git a/ext/server/nino b/ext/server/nino index c772fc51..de778025 160000 --- a/ext/server/nino +++ b/ext/server/nino @@ -1 +1 @@ -Subproject commit c772fc5194d69b91d26666a99ffd051451015fdb +Subproject commit de77802546317cb7561c7172e777ff9bcce50393 diff --git a/library/error/error-safe.ecf b/library/error/error-safe.ecf new file mode 100644 index 00000000..b5eb8493 --- /dev/null +++ b/library/error/error-safe.ecf @@ -0,0 +1,16 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + diff --git a/library/error/error.ecf b/library/error/error.ecf new file mode 100644 index 00000000..ea7b6080 --- /dev/null +++ b/library/error/error.ecf @@ -0,0 +1,16 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + diff --git a/library/error/license.lic b/library/error/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/error/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/error/src/error.e b/library/error/src/error.e new file mode 100644 index 00000000..5687ecac --- /dev/null +++ b/library/error/src/error.e @@ -0,0 +1,80 @@ +note + description : "Objects that represent an error" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class + ERROR + +feature -- Access + + code: INTEGER + deferred + ensure + result_not_zero: Result /= 0 + end + + name: STRING + deferred + ensure + result_attached: Result /= Void + end + + message: detachable STRING_32 + -- Potential error message + deferred + end + + parent: detachable ERROR + -- Eventual error prior to Current + +feature -- String representation + + string_representation: STRING_32 + -- String representation for Current + do + create Result.make_from_string (name.as_string_32) + Result.append_character (' ') + Result.append_character ('(') + Result.append_integer (code) + Result.append_character (')') + if attached message as m then + Result.append_character (':') + Result.append_character (' ') + Result.append_string (m) + end + end + +feature -- Change + + set_parent (a_parent: like parent) + -- Set `parent' to `a_parent' + do + parent := a_parent + end + +feature -- Visitor + + process (a_visitor: ERROR_VISITOR) + -- Process Current using `a_visitor'. + require + a_visitor_not_void: a_visitor /= Void + deferred + end + +invariant + name_attached: name /= Void + +note + copyright: "Copyright (c) 1984-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/error/src/error_custom.e b/library/error/src/error_custom.e new file mode 100644 index 00000000..7b139fab --- /dev/null +++ b/library/error/src/error_custom.e @@ -0,0 +1,57 @@ +note + description : "Objects that represent a custom error" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + ERROR_CUSTOM + +inherit + ERROR + +create + make + +feature {NONE} -- Initialization + + make (a_code: INTEGER; a_name: STRING; a_message: detachable like message) + -- Initialize `Current'. + do + code := a_code + name := a_name + if attached a_message then + message := a_message + else + message := "Error: " + a_name + " (code=" + a_code.out + ")" + end + end + +feature -- Access + + code: INTEGER + + name: STRING + + message: STRING_32 + +feature -- Visitor + + process (a_visitor: ERROR_VISITOR) + -- Process Current using `a_visitor'. + do + a_visitor.process_custom (Current) + end + +note + copyright: "Copyright (c) 1984-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/error/src/error_group.e b/library/error/src/error_group.e new file mode 100644 index 00000000..df101759 --- /dev/null +++ b/library/error/src/error_group.e @@ -0,0 +1,75 @@ +note + description : "Objects that represent a group of errors" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + ERROR_GROUP + +inherit + ERROR + +create + make + +feature {NONE} -- Initialization + + make (a_errors: LIST [ERROR]) + -- Initialize `Current'. + do + name := a_errors.count.out + " errors" + create {ARRAYED_LIST [ERROR]} sub_errors.make (a_errors.count) + sub_errors.fill (a_errors) + end + +feature -- Access + + code: INTEGER = -1 + + name: STRING + + message: detachable STRING_32 + do + create Result.make_from_string (name) + from + sub_errors.start + until + sub_errors.after + loop + if + attached sub_errors.item as e and then + attached e.message as m + then + + Result.append_character ('%N') + Result.append_string (m) + end + sub_errors.forth + end + end + + sub_errors: LIST [ERROR] + -- Error contained by Current + +feature -- Visitor + + process (a_visitor: ERROR_VISITOR) + -- Process Current using `a_visitor'. + do + a_visitor.process_group (Current) + end + + +note + copyright: "Copyright (c) 1984-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/error/src/error_handler.e b/library/error/src/error_handler.e new file mode 100644 index 00000000..1a124b49 --- /dev/null +++ b/library/error/src/error_handler.e @@ -0,0 +1,92 @@ +note + description : "Objects that handle error..." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + ERROR_HANDLER + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + do + create {ARRAYED_LIST [ERROR]} errors.make (3) + end + +feature -- Status + + has_error: BOOLEAN + -- Has error? + do + Result := count > 0 + end + + count: INTEGER + do + Result := errors.count + end + + errors: LIST [ERROR] + -- Errors container + +feature -- Basic operation + + add_error (a_error: ERROR) + -- Add `a_error' to the stack of error + do + errors.force (a_error) + end + + add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable STRING_32) + -- Add custom error to the stack of error + local + e: ERROR_CUSTOM + do + create e.make (a_code, a_name, a_message) + add_error (e) + end + +feature -- Access + + as_single_error: detachable ERROR + do + if count > 1 then + create {ERROR_GROUP} Result.make (errors) + elseif count > 0 then + Result := errors.first + end + end + +feature -- Element changes + + concatenate + -- Concatenate into a single error if any + do + if count > 1 and then attached as_single_error as e then + wipe_out + add_error (e) + end + end + + reset, wipe_out + do + errors.wipe_out + end + +note + copyright: "Copyright (c) 1984-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/error/src/visitor/error_iterator.e b/library/error/src/visitor/error_iterator.e new file mode 100644 index 00000000..0102544a --- /dev/null +++ b/library/error/src/visitor/error_iterator.e @@ -0,0 +1,49 @@ +note + description : "Error list iterator" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + ERROR_ITERATOR + +inherit + ERROR_VISITOR + +feature -- Access + + process_error (e: ERROR) + do + end + + process_custom (e: ERROR_CUSTOM) + do + process_error (e) + end + + process_group (g: ERROR_GROUP) + do + if attached g.sub_errors as err then + from + err.start + until + err.after + loop + process_error (err.item) + err.forth + end + end + end + +note + copyright: "Copyright (c) 1984-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/error/src/visitor/error_null_visitor.e b/library/error/src/visitor/error_null_visitor.e new file mode 100644 index 00000000..24af641c --- /dev/null +++ b/library/error/src/visitor/error_null_visitor.e @@ -0,0 +1,38 @@ +note + description : "Null error visitor" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + ERROR_NULL_VISITOR + +inherit + ERROR_VISITOR + +feature -- Access + + process_error (e: ERROR) + do + end + + process_custom (e: ERROR_CUSTOM) + do + end + + process_group (g: ERROR_GROUP) + do + end + +note + copyright: "Copyright (c) 1984-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/error/src/visitor/error_visitor.e b/library/error/src/visitor/error_visitor.e new file mode 100644 index 00000000..40d205e6 --- /dev/null +++ b/library/error/src/visitor/error_visitor.e @@ -0,0 +1,35 @@ +note + description : "Objects to visit an ERROR" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class + ERROR_VISITOR + +feature -- Access + + process_error (e: ERROR) + deferred + end + + process_custom (e: ERROR_CUSTOM) + deferred + end + + process_group (g: ERROR_GROUP) + deferred + end + +note + copyright: "Copyright (c) 1984-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/error/src/visitor/file_output_error_visitor.e b/library/error/src/visitor/file_output_error_visitor.e new file mode 100644 index 00000000..588c4250 --- /dev/null +++ b/library/error/src/visitor/file_output_error_visitor.e @@ -0,0 +1,53 @@ +note + description: "File error output visitor" + date: "$Date$" + revision: "$Revision$" + +class + FILE_OUTPUT_ERROR_VISITOR + +inherit + OUTPUT_ERROR_VISITOR + redefine + output_integer, + output_new_line + end + +create + make + +feature -- Initialization + + make (f: like file) + require + f_open_write: f /= Void and then f.is_open_write + do + file := f + end + +feature -- Access + + file: FILE + +feature -- Output + + output_string (a_str: detachable STRING_GENERAL) + -- Output Unicode string + do + if a_str /= Void then + to_implement ("Convert into UTF-8 or console encoding before output") + file.put_string (a_str.as_string_8) + end + end + + output_integer (i: INTEGER) + do + file.put_integer (i) + end + + output_new_line + do + file.put_new_line + end + +end diff --git a/library/error/src/visitor/output_error_visitor.e b/library/error/src/visitor/output_error_visitor.e new file mode 100644 index 00000000..22d1128d --- /dev/null +++ b/library/error/src/visitor/output_error_visitor.e @@ -0,0 +1,93 @@ +note + description: "General error output visitor" + date: "$Date$" + revision: "$Revision$" + +deferred class + OUTPUT_ERROR_VISITOR + +inherit + ERROR_VISITOR + + REFACTORING_HELPER + +feature -- Output + + output_string (a_str: detachable STRING_GENERAL) + -- Output Unicode string + deferred + end + + output_any (obj: detachable ANY) + -- Output Unicode string + do + if attached {STRING_GENERAL} obj as l_str then + to_implement ("Convert into UTF-8 or console encoding before output") + output_string (l_str) + elseif obj /= Void then + output_string (obj.out) + end + end + + output_integer (i: INTEGER) + do + output_string (i.out) + end + + output_new_line + do + output_string ("%N") + end + +feature -- Process + + process_error (e: ERROR) + do + output_string ({STRING_32}"Error Name: ") + output_string (e.name) + output_string ({STRING_32}"Code: ") + output_integer (e.code) + output_new_line + output_string ({STRING_32}"%TMessage: ") + output_string (e.message) + output_new_line + end + + process_custom (e: ERROR_CUSTOM) + do + output_string ({STRING_32}"Error Name: ") + output_string (e.name) + output_string ({STRING_32}"Code: ") + output_integer (e.code) + output_new_line + output_string ({STRING_32}"%TMessage: ") + output_string (e.message) + output_new_line + end + + process_group (g: ERROR_GROUP) + local + l_errors: LIST [ERROR] + do + from + l_errors := g.sub_errors + l_errors.start + until + l_errors.after + loop + l_errors.item.process (Current) + l_errors.forth + end + end + +note + copyright: "Copyright (c) 1984-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/error/src/visitor/text_output_error_visitor.e b/library/error/src/visitor/text_output_error_visitor.e new file mode 100644 index 00000000..bff7f86f --- /dev/null +++ b/library/error/src/visitor/text_output_error_visitor.e @@ -0,0 +1,53 @@ +note + description: "Text error output visitor" + date: "$Date$" + revision: "$Revision$" + +class + TEXT_OUTPUT_ERROR_VISITOR + +inherit + OUTPUT_ERROR_VISITOR + redefine + output_integer, + output_new_line + end + +create + make + +feature -- Initialization + + make (buf: like buffer) + require + buf_attached: buf /= Void + do + buffer := buf + end + +feature -- Access + + buffer: STRING + +feature -- Output + + output_string (a_str: detachable STRING_GENERAL) + -- Output Unicode string + do + if a_str /= Void then + to_implement ("Convert into UTF-8 or console encoding before output") + buffer.append_string_general (a_str) + end + end + + output_integer (i: INTEGER) + do + buffer.append_integer (i) + end + + output_new_line + do + buffer.append_character ('%N') + end + +end diff --git a/library/protocol/http/http-safe.ecf b/library/protocol/http/http-safe.ecf new file mode 100644 index 00000000..cee2c04b --- /dev/null +++ b/library/protocol/http/http-safe.ecf @@ -0,0 +1,17 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + diff --git a/library/protocol/http/http.ecf b/library/protocol/http/http.ecf new file mode 100644 index 00000000..f8e77884 --- /dev/null +++ b/library/protocol/http/http.ecf @@ -0,0 +1,18 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + + diff --git a/library/protocol/http/src/http_constants.e b/library/protocol/http/src/http_constants.e new file mode 100644 index 00000000..9569b03f --- /dev/null +++ b/library/protocol/http/src/http_constants.e @@ -0,0 +1,97 @@ +note + description: "Summary description for {HTTP_CONSTANTS}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + HTTP_CONSTANTS + +feature -- Ports + + default_http_port: INTEGER = 80 + default_https_port: INTEGER = 443 + +feature -- Method + + method_get: STRING = "GET" + method_post: STRING = "POST" + method_put: STRING = "PUT" + method_delete: STRING = "DELETE" + method_head: STRING = "HEAD" + method_download: STRING = "DOWNLOAD" + +feature -- Content type + + octet_stream: STRING = "application/octet-stream" + -- Octet stream content-type header + multipart_form: STRING = "multipart/form-data" + -- Starting chars of multipart form data content-type header + form_encoded: STRING = "application/x-www-form-urlencoded" + -- Starting chars of form url-encoded data content-type header + xml_text: STRING = "text/xml" + -- XML text content-type header + html_text: STRING = "text/html" + -- HTML text content-type header + json_text: STRING = "text/json" + -- JSON text content-type header + json_app: STRING = "application/json" + -- JSON application content-type header + js_text: STRING = "text/javascript" + -- Javascript text content-type header + js_app: STRING = "application/javascript" + -- JavaScript application content-type header + plain_text: STRING = "text/plain" + -- Plain text content-type header + +feature -- Server + + http_version_1_0: STRING = "HTTP/1.0" + http_host_header: STRING = "Host" + http_authorization_header: STRING = "Authorization: " + http_end_of_header_line: STRING = "%R%N" + http_end_of_command: STRING = "%R%N%R%N" + http_content_length: STRING = "Content-Length: " + http_content_type: STRING = "Content-Type: " + http_content_location: STRING = "Content-Location: " + http_content_disposition: STRING = "Content-Disposition: " + http_path_translated: STRING = "Path-Translated: " + http_agent: STRING = "User-agent: " + http_from: STRING = "From: " + +feature -- Server: header + + header_host: STRING = "Host" + header_authorization: STRING = "Authorization" + header_content_length: STRING = "Content-Length" + header_content_type: STRING = "Content-Type" + header_content_location: STRING = "Content-Location" + header_content_disposition: STRING = "Content-Disposition" + header_cache_control: STRING = "Cache-Control" + header_path_translated: STRING = "Path-Translated" + header_agent: STRING = "User-Agent" + header_referer: STRING = "Referer" -- Officially mispelled in std + header_location: STRING = "Location" + header_from: STRING = "From" + header_status: STRING = "Status" + header_multipart_tag_value_separator: CHARACTER = ';' + +feature -- Misc + + http_status_ok: STRING = "200 OK" + + default_bufsize: INTEGER = 16384 --| 16K + + +note + copyright: "Copyright (c) 1984-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/protocol/http/src/http_date_time_utilities.e b/library/protocol/http/src/http_date_time_utilities.e new file mode 100644 index 00000000..d24c6b09 --- /dev/null +++ b/library/protocol/http/src/http_date_time_utilities.e @@ -0,0 +1,71 @@ +note + description: "Summary description for {HTTP_DATE_TIME_UTILITIES}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + HTTP_DATE_TIME_UTILITIES + +feature -- Access + + now_utc: DATE_TIME + do + create Result.make_now_utc + end + + epoch: DATE_TIME + once ("THREAD") + create Result.make_from_epoch (0) + end + +feature -- Unix time stamp + + unix_time_stamp (dt: detachable DATE_TIME): INTEGER_64 + -- Unix time stamp from `dt' if attached or from epoch is detached + local + l_date_time: DATE_TIME + do + if dt /= Void then + l_date_time := dt + else + l_date_time := now_utc + end + Result := l_date_time.definite_duration (epoch).seconds_count + end + + fine_unix_time_stamp (dt: detachable DATE_TIME): DOUBLE + -- Fine unix time stamp from `dt' if attached or from epoch is detached + local + l_date_time: DATE_TIME + do + if dt /= Void then + l_date_time := dt + else + l_date_time := now_utc + end + Result := l_date_time.definite_duration (epoch).fine_seconds_count + end + +feature -- Unix time stamp conversion + + unix_time_stamp_to_date_time (i64: INTEGER_64): DATE_TIME + -- Date time related to `i64' + do + create Result.make_from_epoch (i64.as_integer_32) + ensure + same_unix_time_stamp: unix_time_stamp (Result) = i64 + end + +;note + copyright: "Copyright (c) 1984-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/protocol/http/src/http_status_code.e b/library/protocol/http/src/http_status_code.e new file mode 100644 index 00000000..43375c1f --- /dev/null +++ b/library/protocol/http/src/http_status_code.e @@ -0,0 +1,106 @@ +note + description: "[ + Status code constants pertaining to the HTTP protocol + See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + HTTP_STATUS_CODE + +feature -- 1xx : Informational + + continue: INTEGER = 100 + switching_protocols: INTEGER = 101 + processing: INTEGER = 102 -- WebDAV RFC 2518 + ie7_request_uri_too_long: INTEGER = 122 -- non standard, IE7 only + +feature -- 2xx : Success + + ok: INTEGER = 200 + created: INTEGER = 201 + accepted: INTEGER = 202 + nonauthoritative_info: INTEGER = 203 + no_content: INTEGER = 204 + reset_content: INTEGER = 205 + partial_content: INTEGER = 206 + multistatus: INTEGER = 207 -- WebDAV RFC 4918 + im_used: INTEGER = 226 -- RFC 4918 + +feature -- 3xx : Redirection + + multiple_choices: INTEGER = 300 + moved_permanently: INTEGER = 301 + found: INTEGER = 302 + see_other: INTEGER = 303 + not_modified: INTEGER = 304 + use_proxy: INTEGER = 305 + switch_proxy: INTEGER = 306 + temp_redirect: INTEGER = 307 + +feature -- 4xx : Client Error + + bad_request: INTEGER = 400 + unauthorized: INTEGER = 401 + payment_required: INTEGER = 402 + forbidden: INTEGER = 403 + not_found: INTEGER = 404 + method_not_allowed: INTEGER = 405 + not_acceptable: INTEGER = 406 + proxy_auth_required: INTEGER = 407 + request_timeout: INTEGER = 408 + conflict: INTEGER = 409 + gone: INTEGER = 410 + length_required: INTEGER = 411 + precondition_failed: INTEGER = 412 + request_entity_too_large: INTEGER = 413 + request_uri_too_long: INTEGER = 414 + unsupported_media_type: INTEGER = 415 + request_range_not_satisfiable: INTEGER = 416 + expectation_failed: INTEGER = 417 + teapot: INTEGER = 418 + +feature -- 4xx : Client Error : WebDAV errors + + too_many_connections: INTEGER = 421 + unprocessable_entity: INTEGER = 422 + locked: INTEGER = 423 + failed_dependency: INTEGER = 424 + unordered_collection: INTEGER = 425 + + upgrade_required: INTEGER = 426 + no_response: INTEGER = 444 + retry_with: INTEGER = 449 + blocked_parental: INTEGER = 450 + client_closed_request: INTEGER = 499 + +feature -- 5xx : Server Error + + internal_server_error: INTEGER = 500 + not_implemented: INTEGER = 501 + bad_gateway: INTEGER = 502 + service_unavailable: INTEGER = 503 + gateway_timeout: INTEGER = 504 + http_version_not_supported: INTEGER = 505 + variant_also_negotiates: INTEGER = 506 + insufficient_storage: INTEGER = 507 -- WebDAV RFC 4918 + + bandwidth_limit_exceeded: INTEGER = 509 + not_extended: INTEGER = 510 + + user_access_denied: INTEGER = 530 + +note + copyright: "Copyright (c) 1984-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/protocol/http/src/http_status_code_messages.e b/library/protocol/http/src/http_status_code_messages.e new file mode 100644 index 00000000..27b4274b --- /dev/null +++ b/library/protocol/http/src/http_status_code_messages.e @@ -0,0 +1,160 @@ +note + description: "[ + Status code constants pertaining to the HTTP protocol + See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + HTTP_STATUS_CODE_MESSAGES + +inherit + HTTP_STATUS_CODE + +feature -- Status report + + is_valid_http_status_code (v: INTEGER): BOOLEAN + -- Is the given value a valid http status code? + do + Result := v >= continue and v <= user_access_denied + end + +feature -- Status messages + + http_status_code_message (a_code: INTEGER): detachable STRING + -- Header message related to HTTP status code `a_code' + do + inspect a_code + when continue then + Result := "Continue" + when switching_protocols then + Result := "Switching Protocols" + when processing then + Result := "Processing" + when ok then + Result := "OK" + when created then + Result := "Created" + when accepted then + Result := "Accepted" + when nonauthoritative_info then + Result := "Non-Authoritative Information" + when no_content then + Result := "No Content" + when reset_content then + Result := "Reset Content" + when partial_content then + Result := "Partial Content" + when multistatus then + Result := "Multi-Status" + when multiple_choices then + Result := "Multiple Choices" + when moved_permanently then + Result := "Moved Permanently" + when found then + Result := "Found" + when see_other then + Result := "See Other" + when not_modified then + Result := "Not Modified" + when use_proxy then + Result := "Use Proxy" + when switch_proxy then + Result := "Switch Proxy" + when temp_redirect then + Result := "Temporary Redirect" + when bad_request then + Result := "Bad Request" + when unauthorized then + Result := "Unauthorized" + when payment_required then + Result := "Payment Required" + when forbidden then + Result := "Forbidden" + when not_found then + Result := "Not Found" + when method_not_allowed then + Result := "Method Not Allowed" + when not_acceptable then + Result := "Not Acceptable" + when proxy_auth_required then + Result := "Proxy Authentication Required" + when request_timeout then + Result := "Request Timeout" + when conflict then + Result := "Conflict" + when gone then + Result := "Gone" + when length_required then + Result := "Length Required" + when precondition_failed then + Result := "Precondition Failed" + when request_entity_too_large then + Result := "Request Entity Too Large" + when request_uri_too_long then + Result := "Request-URI Too Long" + when unsupported_media_type then + Result := "Unsupported Media Type" + when request_range_not_satisfiable then + Result := "Requested Range Not Satisfiable" + when expectation_failed then + Result := "Expectation Failed" + when teapot then + Result := "I'm a teapot" + when too_many_connections then + Result := "There are too many connections from your internet address" + when unprocessable_entity then + Result := "Unprocessable Entity" + when locked then + Result := "Locked" + when failed_dependency then + Result := "Failed Dependency" + when unordered_collection then + Result := "Unordered Collection" + when upgrade_required then + Result := "Upgrade Required" + when retry_with then + Result := "Retry With" + when blocked_parental then + Result := "Blocked by Windows Parental Controls" + when internal_server_error then + Result := "Internal Server Error" + when not_implemented then + Result := "Not Implemented" + when bad_gateway then + Result := "Bad Gateway" + when service_unavailable then + Result := "Service Unavailable" + when gateway_timeout then + Result := "Gateway Timeout" + when http_version_not_supported then + Result := "HTTP Version Not Supported" + when variant_also_negotiates then + Result := "Variant Also Negotiates" + when insufficient_storage then + Result := "Insufficient Storage" + when bandwidth_limit_exceeded then + Result := "Bandwidth Limit Exceeded" + when not_extended then + Result := "Not Extended" + when user_access_denied then + Result := "User access denied" + else + Result := Void + end + end + +note + copyright: "Copyright (c) 1984-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/ewsgi/COPYRIGHT b/library/server/ewsgi/COPYRIGHT similarity index 100% rename from library/ewsgi/COPYRIGHT rename to library/server/ewsgi/COPYRIGHT diff --git a/library/server/ewsgi/connectors/cgi/cgi-safe.ecf b/library/server/ewsgi/connectors/cgi/cgi-safe.ecf new file mode 100644 index 00000000..a1900388 --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/cgi-safe.ecf @@ -0,0 +1,16 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + diff --git a/library/server/ewsgi/connectors/cgi/cgi.ecf b/library/server/ewsgi/connectors/cgi/cgi.ecf new file mode 100644 index 00000000..412abe6b --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/cgi.ecf @@ -0,0 +1,16 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + diff --git a/library/server/ewsgi/connectors/cgi/license.lic b/library/server/ewsgi/connectors/cgi/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/server/ewsgi/connectors/cgi/src/gw_cgi_connector.e b/library/server/ewsgi/connectors/cgi/src/gw_cgi_connector.e new file mode 100644 index 00000000..d229eee7 --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/src/gw_cgi_connector.e @@ -0,0 +1,36 @@ +note + description: "Summary description for {GW_CGI_CONNECTOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + GW_CGI_CONNECTOR + +inherit + GW_CONNECTOR + +create + make + +feature -- Execution + + launch + local + env: GW_ENVIRONMENT_VARIABLES + do + create env.make_with_variables ((create {EXECUTION_ENVIRONMENT}).starting_environment_variables) + application.process (env, create {GW_CGI_INPUT_STREAM}.make, create {GW_CGI_OUTPUT_STREAM}.make) + end + +note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/cgi/src/gw_cgi_input_stream.e b/library/server/ewsgi/connectors/cgi/src/gw_cgi_input_stream.e new file mode 100644 index 00000000..0a49425d --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/src/gw_cgi_input_stream.e @@ -0,0 +1,39 @@ +note + description: "Summary description for GW_CGI_INPUT_STREAM." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_CGI_INPUT_STREAM + +inherit + GW_INPUT_STREAM + + CONSOLE + rename + make as console_make + end + +create + make + +feature {NONE} -- Initialization + + make + do + make_open_stdin ("stdin") + 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/ewsgi/connectors/cgi/src/gw_cgi_output_stream.e b/library/server/ewsgi/connectors/cgi/src/gw_cgi_output_stream.e new file mode 100644 index 00000000..7a05d8ca --- /dev/null +++ b/library/server/ewsgi/connectors/cgi/src/gw_cgi_output_stream.e @@ -0,0 +1,39 @@ +note + description: "Summary description for GW_CGI_OUTPUT_STREAM." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_CGI_OUTPUT_STREAM + +inherit + GW_OUTPUT_STREAM + + CONSOLE + rename + make as console_make + end + +create + make + +feature {NONE} -- Initialization + + make + do + make_open_stdout ("stdout") + 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/ewsgi/connectors/libfcgi/libfcgi-safe.ecf b/library/server/ewsgi/connectors/libfcgi/libfcgi-safe.ecf new file mode 100644 index 00000000..d02b81dd --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/libfcgi-safe.ecf @@ -0,0 +1,17 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + diff --git a/library/server/ewsgi/connectors/libfcgi/libfcgi.ecf b/library/server/ewsgi/connectors/libfcgi/libfcgi.ecf new file mode 100644 index 00000000..3eb715f7 --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/libfcgi.ecf @@ -0,0 +1,17 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + diff --git a/library/server/ewsgi/connectors/libfcgi/license.lic b/library/server/ewsgi/connectors/libfcgi/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_connector.e b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_connector.e new file mode 100644 index 00000000..91def76e --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_connector.e @@ -0,0 +1,81 @@ +note + description: "Summary description for {GW_LIBFCGI_CONNECTOR}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_LIBFCGI_CONNECTOR + +inherit + GW_CONNECTOR + redefine + initialize + end + +create + make + +feature {NONE} -- Initialization + + initialize + do + create fcgi.make + create {GW_LIBFCGI_INPUT_STREAM} input.make (fcgi) + create {GW_LIBFCGI_OUTPUT_STREAM} output.make (fcgi) + end + +feature -- Server + + launch + local + res: INTEGER + do + from + res := fcgi.fcgi_listen + until + res < 0 + loop + process_fcgi_request (fcgi.updated_environ_variables, input, output) + res := fcgi.fcgi_listen + end + end + +feature -- Execution + + process_fcgi_request (vars: HASH_TABLE [STRING, STRING]; a_input: like input; a_output: like output) + local + gw_env: GW_ENVIRONMENT_VARIABLES + do + create gw_env.make_with_variables (vars) + application.process (gw_env, a_input, a_output) + end + +feature -- Input/Output + + input: GW_INPUT_STREAM + -- Input from client (from httpd server via FCGI) + + output: GW_OUTPUT_STREAM + -- Output to client (via httpd server/fcgi) + +feature {NONE} -- Implementation + + fcgi: FCGI + +invariant + fcgi_attached: fcgi /= Void + +note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/libfcgi/src/gw_libfcgi_input_stream.e b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_input_stream.e new file mode 100644 index 00000000..75db59d7 --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_input_stream.e @@ -0,0 +1,66 @@ +note + description: "Summary description for GW_LIBFCGI_INPUT_STREAM." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_LIBFCGI_INPUT_STREAM + +inherit + GW_INPUT_STREAM + + STRING_HANDLER + +create + make + +feature {NONE} -- Initialization + + make (a_fcgi: like fcgi) + require + valid_fcgi: a_fcgi /= Void + do + fcgi := a_fcgi + initialize + end + + initialize + -- Initialize Current + do + create last_string.make_empty + end + +feature -- Basic operation + + read_stream (nb_char: INTEGER) + -- Read a string of at most `nb_char' bound characters + -- or until end of file. + -- Make result available in `last_string'. + do + fcgi.fill_string_from_stdin (last_string, nb_char) + end + +feature -- Access + + last_string: STRING + -- Last string read + +feature {NONE} -- Implementation + + fcgi: FCGI; + -- Bridge to FCGI world + +note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/libfcgi/src/gw_libfcgi_output_stream.e b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_output_stream.e new file mode 100644 index 00000000..331bb763 --- /dev/null +++ b/library/server/ewsgi/connectors/libfcgi/src/gw_libfcgi_output_stream.e @@ -0,0 +1,57 @@ +note + description: "Summary description for {GW_LIBFCGI_OUTPUT_STREAM}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_LIBFCGI_OUTPUT_STREAM + +inherit + GW_OUTPUT_STREAM + +create + make + +feature {NONE} -- Initialization + + make (a_fcgi: like fcgi) + require + valid_fcgi: a_fcgi /= Void + do + fcgi := a_fcgi + end + +feature -- Basic operation + + put_string (s: STRING) + -- Send `s' to http client + do + fcgi.put_string (s) + end + + flush + do + end + +feature {NONE} -- Implementation + + fcgi: FCGI + -- Bridge to FCGI world + +invariant + fcgi_attached: fcgi /= Void + +note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/nino/license.lic b/library/server/ewsgi/connectors/nino/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/server/ewsgi/connectors/nino/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/server/ewsgi/connectors/nino/nino-safe.ecf b/library/server/ewsgi/connectors/nino/nino-safe.ecf new file mode 100644 index 00000000..1b3cbefb --- /dev/null +++ b/library/server/ewsgi/connectors/nino/nino-safe.ecf @@ -0,0 +1,17 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + diff --git a/library/server/ewsgi/connectors/nino/nino.ecf b/library/server/ewsgi/connectors/nino/nino.ecf new file mode 100644 index 00000000..97a1099a --- /dev/null +++ b/library/server/ewsgi/connectors/nino/nino.ecf @@ -0,0 +1,17 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + diff --git a/library/server/ewsgi/connectors/nino/src/gw_nino_connector.e b/library/server/ewsgi/connectors/nino/src/gw_nino_connector.e new file mode 100644 index 00000000..c14bcc8a --- /dev/null +++ b/library/server/ewsgi/connectors/nino/src/gw_nino_connector.e @@ -0,0 +1,93 @@ +note + description: "Summary description for {GW_NINO_CONNECTOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + GW_NINO_CONNECTOR + +inherit + GW_CONNECTOR + redefine + initialize + end + +create + make, + make_with_base + +feature {NONE} -- Initialization + + make_with_base (a_app: like application; a_base: like base) + do + make (a_app) + base := a_base + end + +feature {NONE} -- Initialization + + initialize + local + cfg: HTTP_SERVER_CONFIGURATION + do + create cfg.make + create server.make (cfg) + end + +feature -- Access + + server: HTTP_SERVER + + configuration: HTTP_SERVER_CONFIGURATION + do + Result := server.configuration + end + +feature -- Access + + base: detachable STRING + -- Root url base + +feature -- Element change + + set_base (b: like base) + do + base := b + end + +feature -- Server + + launch + local + l_http_handler : HTTP_HANDLER + do + create {GW_NINO_HANDLER} l_http_handler.make_with_callback (server, "GW_NINO_HANDLER", Current) + debug ("nino") + if attached base as l_base then + print ("Base=" + l_base + "%N") + end + end + server.setup (l_http_handler) + end + + process_request (env: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM) + local + gw_env: GW_ENVIRONMENT_VARIABLES + do + create gw_env.make_with_variables (env) + gw_env.set_variable ("RAW_HEADER_DATA", a_headers_text) + application.process (gw_env, create {GW_NINO_INPUT_STREAM}.make (a_input), create {GW_NINO_OUTPUT_STREAM}.make (a_output)) + end + +note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/nino/src/gw_nino_handler.e b/library/server/ewsgi/connectors/nino/src/gw_nino_handler.e new file mode 100644 index 00000000..264ba393 --- /dev/null +++ b/library/server/ewsgi/connectors/nino/src/gw_nino_handler.e @@ -0,0 +1,156 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + GW_NINO_HANDLER + +inherit + HTTP_CONNECTION_HANDLER + +create + make_with_callback + +feature {NONE} -- Initialization + + make_with_callback (a_main_server: like main_server; a_name: STRING; a_callback: like callback) + -- Initialize `Current'. + do + make (a_main_server, a_name) + callback := a_callback + end + + callback: GW_NINO_CONNECTOR + +feature -- Access + + base: detachable STRING + -- Root url base + +feature -- Element change + + set_base (a_uri: like base) + -- Set `base' to `a_uri' + do + base := a_uri + end + +feature -- Request processing + + process_request (a_handler: HTTP_CONNECTION_HANDLER; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM) + -- Process request ... + local + env, vars: HASH_TABLE [STRING, STRING] + p: INTEGER + l_request_uri, l_script_name, l_query_string, l_path_info: STRING + l_server_name, l_server_port: detachable STRING + a_headers_map: HASH_TABLE [STRING, STRING] + vn: STRING + + e: EXECUTION_ENVIRONMENT + do + l_request_uri := a_handler.uri + a_headers_map := a_handler.request_header_map + create e + vars := e.starting_environment_variables + env := vars.twin + + --| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env' + from + a_headers_map.start + until + a_headers_map.after + loop + vn := a_headers_map.key_for_iteration.as_upper + vn.replace_substring_all ("-", "_") + add_environment_variable (a_headers_map.item_for_iteration, vn, env) + a_headers_map.forth + end + + --| Specific cases + + p := l_request_uri.index_of ('?', 1) + if p > 0 then + l_script_name := l_request_uri.substring (1, p - 1) + l_query_string := l_request_uri.substring (p + 1, l_request_uri.count) + else + l_script_name := l_request_uri.string + l_query_string := "" + end + if attached a_headers_map.item ("Host") as l_host then + add_environment_variable (l_host, "HTTP_HOST", env) + p := l_host.index_of (':', 1) + if p > 0 then + l_server_name := l_host.substring (1, p - 1) + l_server_port := l_host.substring (p+1, l_host.count) + else + l_server_name := l_host + l_server_port := "80" -- Default + end + end + + if attached a_headers_map.item ("Authorization") as l_authorization then + add_environment_variable (l_authorization, "HTTP_AUTHORIZATION", env) + p := l_authorization.index_of (' ', 1) + if p > 0 then + add_environment_variable (l_authorization.substring (1, p - 1), "AUTH_TYPE", env) + end + end + + add_environment_variable ("CGI/1.1", "GATEWAY_INTERFACE", env) + add_environment_variable (l_query_string, "QUERY_STRING", env) + + if attached a_handler.remote_info as l_remote_info then + add_environment_variable (l_remote_info.addr, "REMOTE_ADDR", env) + add_environment_variable (l_remote_info.hostname, "REMOTE_HOST", env) + add_environment_variable (l_remote_info.port.out, "REMOTE_PORT", env) +-- add_environment_variable (Void, "REMOTE_IDENT", env) +-- add_environment_variable (Void, "REMOTE_USER", env) + end + + add_environment_variable (l_request_uri, "REQUEST_URI", env) + add_environment_variable (a_handler.method, "REQUEST_METHOD", env) + + add_environment_variable (l_script_name, "SCRIPT_NAME", env) + add_environment_variable (l_server_name, "SERVER_NAME", env) + add_environment_variable (l_server_port, "SERVER_PORT", env) + add_environment_variable (a_handler.version, "SERVER_PROTOCOL", env) + add_environment_variable ({HTTP_SERVER_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", env) + + --| Apply `base' value + if attached base as l_base and then l_request_uri /= Void then + if l_request_uri.starts_with (l_base) then + l_path_info := l_request_uri.substring (l_base.count + 1, l_request_uri.count) + p := l_path_info.index_of ('?', 1) + if p > 0 then + l_path_info.keep_head (p - 1) + end + env.force (l_path_info, "PATH_INFO") + env.force (l_base, "SCRIPT_NAME") + end + end + + callback.process_request (env, a_handler.request_header, a_input, a_output) + end + + add_environment_variable (a_value: detachable STRING; a_var_name: STRING; env: HASH_TABLE [STRING, STRING]) + -- Add variable `a_var_name => a_value' to `env' + do + if a_value /= Void then + env.force (a_value, a_var_name) + end + 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/ewsgi/connectors/nino/src/gw_nino_input_stream.e b/library/server/ewsgi/connectors/nino/src/gw_nino_input_stream.e new file mode 100644 index 00000000..a5f97038 --- /dev/null +++ b/library/server/ewsgi/connectors/nino/src/gw_nino_input_stream.e @@ -0,0 +1,61 @@ +note + description: "Summary description for {GW_NINO_INPUT_STREAM}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_NINO_INPUT_STREAM + +inherit + GW_INPUT_STREAM + +create + make + +feature {NONE} -- Initialization + + make (a_nino_input: like nino_input) + do + create last_string.make_empty + set_nino_input (a_nino_input) + end + +feature {GW_NINO_APPLICATION} -- Nino + + set_nino_input (i: like nino_input) + do + nino_input := i + end + + nino_input: HTTP_INPUT_STREAM + +feature -- Basic operation + + read_stream (nb_char: INTEGER) + -- Read a string of at most `nb_char' bound characters + -- or until end of file. + -- Make result available in `last_string'. + do + nino_input.read_stream (nb_char) + last_string := nino_input.last_string + end + +feature -- Access + + last_string: STRING + -- Last string read + +;note + copyright: "Copyright (c) 1984-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/ewsgi/connectors/nino/src/gw_nino_output_stream.e b/library/server/ewsgi/connectors/nino/src/gw_nino_output_stream.e new file mode 100644 index 00000000..ff4b3e75 --- /dev/null +++ b/library/server/ewsgi/connectors/nino/src/gw_nino_output_stream.e @@ -0,0 +1,60 @@ +note + description: "Summary description for {GW_NINO_OUTPUT_STREAM}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_NINO_OUTPUT_STREAM + +inherit + GW_OUTPUT_STREAM + +create + make + +feature {NONE} -- Initialization + + make (a_nino_output: like nino_output) + do + set_nino_output (a_nino_output) + end + +feature {GW_NINO_APPLICATION} -- Nino + + set_nino_output (o: like nino_output) + do + nino_output := o + end + + nino_output: HTTP_OUTPUT_STREAM + +feature -- Basic operation + + put_string (s: STRING_8) + -- Send `s' to http client + do + debug ("nino") + print (s) + end + nino_output.put_string (s) + end + + flush + -- Flush the output stream + do + 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/ewsgi/doc/cgi_spec_1.0.txt b/library/server/ewsgi/doc/cgi_spec_1.0.txt similarity index 100% rename from library/ewsgi/doc/cgi_spec_1.0.txt rename to library/server/ewsgi/doc/cgi_spec_1.0.txt diff --git a/library/ewsgi/doc/cgi_spec_1.2.txt b/library/server/ewsgi/doc/cgi_spec_1.2.txt similarity index 100% rename from library/ewsgi/doc/cgi_spec_1.2.txt rename to library/server/ewsgi/doc/cgi_spec_1.2.txt diff --git a/library/ewsgi/ewsgi.ecf b/library/server/ewsgi/ewsgi-safe.ecf similarity index 81% rename from library/ewsgi/ewsgi.ecf rename to library/server/ewsgi/ewsgi-safe.ecf index fe78d298..578a1c68 100644 --- a/library/ewsgi/ewsgi.ecf +++ b/library/server/ewsgi/ewsgi-safe.ecf @@ -11,10 +11,8 @@ - - - GW_REQUEST_CONTEXT_IMP - - + + + diff --git a/library/server/ewsgi/ewsgi.ecf b/library/server/ewsgi/ewsgi.ecf new file mode 100644 index 00000000..ca19856a --- /dev/null +++ b/library/server/ewsgi/ewsgi.ecf @@ -0,0 +1,18 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + diff --git a/library/server/ewsgi/examples/hello_world/hello-safe.ecf b/library/server/ewsgi/examples/hello_world/hello-safe.ecf new file mode 100644 index 00000000..bc9bc974 --- /dev/null +++ b/library/server/ewsgi/examples/hello_world/hello-safe.ecf @@ -0,0 +1,19 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + diff --git a/library/server/ewsgi/examples/hello_world/src/hello_world.e b/library/server/ewsgi/examples/hello_world/src/hello_world.e new file mode 100644 index 00000000..59649b48 --- /dev/null +++ b/library/server/ewsgi/examples/hello_world/src/hello_world.e @@ -0,0 +1,58 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + HELLO_WORLD + +inherit + GW_APPLICATION_IMP + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + local + conn: detachable GW_CONNECTOR + nino_conn: GW_NINO_CONNECTOR + do + if is_nino then + create nino_conn.make_with_base (Current, "/hello_world") + if attached nino_conn.server.server_configuration as cfg then + cfg.http_server_port := 8080 + cfg.force_single_threaded := True + end + conn := nino_conn + elseif is_cgi then + create {GW_CGI_CONNECTOR} conn.make (Current) + elseif is_libfcgi then + create {GW_LIBFCGI_CONNECTOR} conn.make (Current) + else + io.error.put_string ("Unsupported connector") + end + if conn /= Void then + conn.launch + end + end + + is_nino: BOOLEAN = True + is_cgi: BOOLEAN = False + is_libfcgi: BOOLEAN = False + +feature -- Execution + + execute (ctx: GW_REQUEST_CONTEXT) + -- Execute the request + do + ctx.output.put_string ("Hello World!%N") + if attached ctx.execution_variable ("REQUEST_COUNT") as rq_count then + ctx.output.put_string ("Request #" + rq_count + "%N") + end + end + +end diff --git a/library/ewsgi/license.lic b/library/server/ewsgi/license.lic similarity index 100% rename from library/ewsgi/license.lic rename to library/server/ewsgi/license.lic diff --git a/library/ewsgi/src/gw_environment.e b/library/server/ewsgi/src/context/gw_environment.e similarity index 95% rename from library/ewsgi/src/gw_environment.e rename to library/server/ewsgi/src/context/gw_environment.e index 2a974d52..1c7f4146 100644 --- a/library/ewsgi/src/gw_environment.e +++ b/library/server/ewsgi/src/context/gw_environment.e @@ -143,19 +143,19 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 auth_type: detachable STRING -- 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 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 -- request header included an "Authorization" field that was -- authenticated. @@ -169,9 +169,9 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 -- request was accompanied by a message-body entity. deferred @@ -189,7 +189,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 @@ -197,16 +197,16 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 @@ -214,7 +214,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- application/octet-stream or reject the 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 request -- header. If the server receives a request with an attached @@ -228,23 +228,23 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 gateway_interface: STRING -- 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: -- @@ -258,7 +258,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 deferred end - path_info: STRING + path_info: STRING assign update_path_info -- 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 @@ -267,21 +267,21 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 @@ -297,27 +297,27 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- map it onto the server's document repository structure. If the -- request URI includes no path-info component, the -- PATH_TRANSLATED metavariable SHOULD NOT be defined. - -- - -- + -- + -- -- PATH_TRANSLATED = *CHAR - -- + -- -- For a 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 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 @@ -325,11 +325,11 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 request URI includes a path-info component. deferred @@ -338,13 +338,13 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 query_string: STRING -- 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 @@ -356,13 +356,13 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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). - -- + -- -- 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. deferred end @@ -373,7 +373,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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. deferred end @@ -383,12 +383,12 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- RFC 1413 [11] request to the remote agent, if available. -- Servers MAY choose not to support this feature, or not to -- 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. deferred @@ -400,12 +400,12 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- "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. deferred end @@ -415,18 +415,18 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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 -- 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. deferred end @@ -436,15 +436,15 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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. deferred end @@ -453,9 +453,9 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- 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. deferred end @@ -464,13 +464,13 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- The SERVER_PORT metavariable is set to the port on which the -- 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 request was received MUST be -- supplied. - -- + -- -- Servers MUST provide this metavariable to scripts. deferred end @@ -480,25 +480,25 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- revision of the information protocol with which the 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 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 request. - -- + -- -- Servers MUST provide this metavariable to scripts. deferred end @@ -507,7 +507,7 @@ feature -- Common Gateway Interface - 1.1 8 January 1996 -- The SERVER_SOFTWARE metavariable is set to the name and -- version of the information server software answering the -- request (and running the gateway). - -- + -- -- SERVER_SOFTWARE = 1*product -- product = token [ "/" product-version ] -- product-version = token @@ -581,6 +581,31 @@ feature -- Extra deferred end +feature {GW_REQUEST_CONTEXT} -- Element change + + set_orig_path_info (s: STRING) + -- Set ORIG_PATH_INFO to `s' + require + s_attached: s /= Void + deferred + ensure + same_orig_path_info: orig_path_info ~ variable ({GW_ENVIRONMENT_NAMES}.orig_path_info) + end + + unset_orig_path_info + -- Unset ORIG_PATH_INFO + deferred + ensure + unset: not has_variable ({GW_ENVIRONMENT_NAMES}.orig_path_info) + end + + update_path_info (a_path_info: like path_info) + -- Updated PATH_INFO + deferred + ensure + same_path_info: path_info ~ variable ({GW_ENVIRONMENT_NAMES}.path_info) + end + invariant server_name_not_empty: not server_name.is_empty server_port_set: server_port /= 0 @@ -589,6 +614,8 @@ invariant query_string_attached: query_string /= Void remote_addr_attached: remote_addr /= Void + path_info_identical: path_info ~ variable ({GW_ENVIRONMENT_NAMES}.path_info) + ;note copyright: "2011-2011, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/server/ewsgi/src/context/gw_environment_variables.e b/library/server/ewsgi/src/context/gw_environment_variables.e new file mode 100644 index 00000000..392dbd3d --- /dev/null +++ b/library/server/ewsgi/src/context/gw_environment_variables.e @@ -0,0 +1,292 @@ +note + description: "Summary description for {GW_ENVIRONMENT_VARIABLES}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_ENVIRONMENT_VARIABLES + +inherit + GW_ENVIRONMENT + redefine + update_path_info + end + +create + make_with_variables + +feature {NONE} -- Initialization + + make_with_variables (a_vars: HASH_TABLE [STRING, STRING]) + -- Fill with variable from `a_vars' + local + s: detachable STRING + do + create empty_string.make_empty + + create table.make (a_vars.count) + from + a_vars.start + until + a_vars.after + loop + table.force (a_vars.item_for_iteration, a_vars.key_for_iteration) + a_vars.forth + end + + --| QUERY_STRING + query_string := variable_or_default ({GW_ENVIRONMENT_NAMES}.query_string, empty_string, False) + + --| REQUEST_METHOD + request_method := variable_or_default ({GW_ENVIRONMENT_NAMES}.request_method, empty_string, False) + + --| CONTENT_TYPE + s := variable ({GW_ENVIRONMENT_NAMES}.content_type) + if s /= Void and then not s.is_empty then + content_type := s + else + content_type := Void + end + + --| CONTENT_LENGTH + s := variable ({GW_ENVIRONMENT_NAMES}.content_length) + content_length := s + if s /= Void and then s.is_integer then + content_length_value := s.to_integer + else + --| content_length := 0 + end + + --| PATH_INFO + path_info := variable_or_default ({GW_ENVIRONMENT_NAMES}.path_info, empty_string, False) + + --| SERVER_NAME + server_name := variable_or_default ({GW_ENVIRONMENT_NAMES}.server_name, empty_string, False) + + --| SERVER_PORT + s := variable ({GW_ENVIRONMENT_NAMES}.server_port) + if s /= Void and then s.is_integer then + server_port := s.to_integer + else + server_port := 80 + end + + --| SCRIPT_NAME + script_name := variable_or_default ({GW_ENVIRONMENT_NAMES}.script_name, empty_string, False) + + --| REMOTE_ADDR + remote_addr := variable_or_default ({GW_ENVIRONMENT_NAMES}.remote_addr, empty_string, False) + + --| REMOTE_HOST + remote_host := variable_or_default ({GW_ENVIRONMENT_NAMES}.remote_host, empty_string, False) + + --| REQUEST_URI + request_uri := variable_or_default ({GW_ENVIRONMENT_NAMES}.request_uri, empty_string, False) + end + +feature -- Access + + table: HASH_TABLE [STRING, STRING] + +feature -- Access + + variable (a_name: STRING): detachable STRING + do + Result := table.item (a_name) + end + + has_variable (a_name: STRING): BOOLEAN + do + Result := table.has_key (a_name) + end + +feature {GW_REQUEST_CONTEXT, GW_APPLICATION, GW_CONNECTOR} -- Element change + + set_variable (a_name: STRING; a_value: STRING) + do + table.force (a_value, a_name) + end + + unset_variable (a_name: STRING) + do + table.remove (a_name) + end + +feature -- Common Gateway Interface - 1.1 8 January 1996 + + auth_type: detachable STRING + + content_length: detachable STRING + + content_length_value: INTEGER + + content_type: detachable STRING + + gateway_interface: STRING + do + Result := variable_or_default ({GW_ENVIRONMENT_NAMES}.gateway_interface, "", False) + end + + path_info: STRING + -- + -- + --| For instance, if the current script was accessed via the URL + --| http://www.example.com/eiffel/path_info.exe/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain /some/stuff. + --| + --| Note that is the PATH_INFO variable does not exists, the `path_info' value will be empty + + path_translated: detachable STRING + do + Result := variable ({GW_ENVIRONMENT_NAMES}.path_translated) + end + + query_string: STRING + + remote_addr: STRING + + remote_host: STRING + + remote_ident: detachable STRING + do + Result := variable ({GW_ENVIRONMENT_NAMES}.remote_ident) + end + + remote_user: detachable STRING + do + Result := variable ({GW_ENVIRONMENT_NAMES}.remote_user) + end + + request_method: STRING + + script_name: STRING + + server_name: STRING + + server_port: INTEGER + + server_protocol: STRING + do + Result := variable_or_default ({GW_ENVIRONMENT_NAMES}.server_protocol, "HTTP/1.0", True) + end + + server_software: STRING + do + Result := variable_or_default ({GW_ENVIRONMENT_NAMES}.server_software, "Unknown Server", True) + end + +feature -- HTTP_* + + http_accept: detachable STRING + -- Contents of the Accept: header from the current request, if there is one. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_accept) + end + + http_accept_charset: detachable STRING + -- Contents of the Accept-Charset: header from the current request, if there is one. + -- Example: 'iso-8859-1,*,utf-8'. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_accept_charset) + end + + http_accept_encoding: detachable STRING + -- Contents of the Accept-Encoding: header from the current request, if there is one. + -- Example: 'gzip'. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_accept_encoding) + end + + http_accept_language: detachable STRING + -- Contents of the Accept-Language: header from the current request, if there is one. + -- Example: 'en'. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_accept_language) + end + + http_connection: detachable STRING + -- Contents of the Connection: header from the current request, if there is one. + -- Example: 'Keep-Alive'. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_connection) + end + + http_host: detachable STRING + -- Contents of the Host: header from the current request, if there is one. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_host) + end + + http_referer: detachable STRING + -- 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 := table.item ({GW_ENVIRONMENT_NAMES}.http_referer) + end + + http_user_agent: detachable STRING + -- 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). + -- Among other things, you can use this value to tailor your page's + -- output to the capabilities of the user agent. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_user_agent) + end + + http_authorization: detachable STRING + -- Contents of the Authorization: header from the current request, if there is one. + do + Result := table.item ({GW_ENVIRONMENT_NAMES}.http_authorization) + end + +feature -- Extra + + request_uri: STRING + -- The URI which was given in order to access this page; for instance, '/index.html'. + + orig_path_info: detachable STRING + -- Original version of `path_info' before processed by Current environment + +feature {GW_REQUEST_CONTEXT} -- Update + + set_orig_path_info (s: STRING) + do + orig_path_info := s + set_variable ({GW_ENVIRONMENT_NAMES}.orig_path_info, s) + end + + unset_orig_path_info + do + orig_path_info := Void + unset_variable ({GW_ENVIRONMENT_NAMES}.orig_path_info) + end + + update_path_info (a_path_info: like path_info) + do + path_info := a_path_info + set_variable ({GW_ENVIRONMENT_NAMES}.path_info, a_path_info) + end + +feature {NONE} -- Implementation + + empty_string: STRING + -- Reusable empty string + +invariant + empty_string_unchanged: empty_string.is_empty + +;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/ewsgi/src/gw_execution_variables.e b/library/server/ewsgi/src/context/gw_execution_variables.e similarity index 70% rename from library/ewsgi/src/gw_execution_variables.e rename to library/server/ewsgi/src/context/gw_execution_variables.e index 8d0f02fa..7408955c 100644 --- a/library/ewsgi/src/gw_execution_variables.e +++ b/library/server/ewsgi/src/context/gw_execution_variables.e @@ -31,29 +31,16 @@ feature -- Status report Result := has (a_name) end -feature -- Element change +feature {GW_REQUEST_CONTEXT, GW_APPLICATION, GW_CONNECTOR} -- Element change - replace_variable (v: STRING; k: STRING) - -- Replace variable `k' + set_variable (a_name: STRING; a_value: STRING_32) do - force (v, k) + force (a_value, a_name) end - add_variable (v: STRING; k: STRING) - -- Add variable `k' with value `v' - require - k_attached: k /= Void - v_attached: k /= Void + unset_variable (a_name: STRING) do - force (v, k) - end - - delete_variable (k: STRING) - -- Remove variable `k' - require - k_attached: k /= Void - do - remove (k) + remove (a_name) end note diff --git a/library/ewsgi/src/gw_request_context.e b/library/server/ewsgi/src/context/gw_request_context.e similarity index 85% rename from library/ewsgi/src/gw_request_context.e rename to library/server/ewsgi/src/context/gw_request_context.e index d4bb4966..e6d62060 100644 --- a/library/ewsgi/src/gw_request_context.e +++ b/library/server/ewsgi/src/context/gw_request_context.e @@ -17,13 +17,13 @@ deferred class feature -- Access: Input/Output - output: GW_OUTPUT_STREAM - -- Server output channel + input: GW_INPUT_STREAM + -- Server input channel deferred end - input: GW_INPUT_STREAM - -- Server input channel + output: GW_OUTPUT_STREAM + -- Server output channel deferred end @@ -31,8 +31,8 @@ feature -- Access: global variable variables: HASH_TABLE [STRING_32, STRING_32] -- Table containing all the various variables - -- Warning: this is computed each time, if you change this content of other container - -- this won't update this Result's content. + -- 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 local vars: HASH_TABLE [STRING_GENERAL, STRING_GENERAL] do @@ -100,11 +100,11 @@ feature -- Access: global variable if s = Void then s := environment_variable (n8) if s = Void then - s := parameters.variable (n8) + s := parameter (n8) if s = Void then - s := form_fields.variable (n8) + s := form_field (n8) if s = Void then - s := cookies_variables.item (n8) + s := cookies_variable (n8) end end end @@ -114,6 +114,13 @@ feature -- Access: global variable end end +feature -- Access: environment extra values + + request_time: detachable DATE_TIME + -- Request time (UTC) + deferred + end + feature -- Access: environment variables environment: GW_ENVIRONMENT @@ -144,13 +151,27 @@ feature -- Access: execution variables Result := execution_variables.variable (a_name) end -feature -- Queries +feature -- URL Parameters + + parameter (n: STRING): detachable STRING_32 + -- Parameter for name `n'. + do + Result := parameters.variable (n) + end parameters: GW_REQUEST_VARIABLES -- Variables extracted from QUERY_STRING deferred end +feature -- Form fields and related + + form_field (n: STRING): detachable STRING_32 + -- Field for name `n'. + do + Result := form_fields.variable (n) + end + form_fields: GW_REQUEST_VARIABLES -- Variables sent by POST request deferred @@ -164,6 +185,16 @@ feature -- Queries --| 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_variable (n: STRING): detachable STRING + -- Field for name `n'. + do + Result := cookies_variables.item (n) + end cookies_variables: HASH_TABLE [STRING, STRING] -- Expanded cookies variable diff --git a/library/ewsgi/src/gw_request_variables.e b/library/server/ewsgi/src/context/gw_request_variables.e similarity index 82% rename from library/ewsgi/src/gw_request_variables.e rename to library/server/ewsgi/src/context/gw_request_variables.e index a3f6850c..00fc5069 100644 --- a/library/ewsgi/src/gw_request_variables.e +++ b/library/server/ewsgi/src/context/gw_request_variables.e @@ -16,8 +16,8 @@ inherit ITERABLE [STRING_32] create - make--, --- make_from_urlencoded + make, + make_from_urlencoded feature -- Initialization @@ -27,11 +27,11 @@ feature -- Initialization table.compare_objects end --- make_from_urlencoded (a_content: STRING; decoding: BOOLEAN) --- do --- make (a_content.occurrences ('&') + 1) --- import_urlencoded (a_content, decoding) --- end + make_from_urlencoded (a_content: STRING; decoding: BOOLEAN) + do + make (a_content.occurrences ('&') + 1) + import_urlencoded (a_content, decoding) + end feature -- Status report @@ -51,15 +51,28 @@ feature -- Status report Result := table.has (a_name) end +feature {GW_REQUEST_CONTEXT, GW_APPLICATION, GW_CONNECTOR} -- Element change + + set_variable (a_name: STRING; a_value: STRING_32) + do + table.force (a_value, a_name) + end + + unset_variable (a_name: STRING) + do + table.remove (a_name) + end + feature -- Import urlencoded --- import_urlencoded (a_content: STRING; decoding: BOOLEAN) --- -- Import `a_content' --- local + import_urlencoded (a_content: STRING; decoding: BOOLEAN) + -- Import `a_content' + local -- n, p, i, j: INTEGER -- s: STRING -- l_name,l_value: STRING_32 --- do + do +-- FIXME -- n := a_content.count -- if n > 0 then -- from @@ -89,7 +102,7 @@ feature -- Import urlencoded -- end -- end -- end --- end + end feature -- Access: table diff --git a/library/ewsgi/src/gw_variables.e b/library/server/ewsgi/src/context/gw_variables.e similarity index 75% rename from library/ewsgi/src/gw_variables.e rename to library/server/ewsgi/src/context/gw_variables.e index 9aac05a8..818eda07 100644 --- a/library/ewsgi/src/gw_variables.e +++ b/library/server/ewsgi/src/context/gw_variables.e @@ -46,6 +46,24 @@ feature -- Access end end +feature {GW_REQUEST_CONTEXT, GW_APPLICATION, GW_CONNECTOR} -- Element change + + set_variable (a_name: STRING; a_value: G) + require + a_name_not_empty: a_name /= Void and then not a_name.is_empty + deferred + ensure + variable_set: has_variable (a_name) and then variable (a_name) ~ a_value + end + + unset_variable (a_name: STRING) + require + a_name_not_empty: a_name /= Void and then not a_name.is_empty + deferred + ensure + variable_unset: not has_variable (a_name) + end + note copyright: "2011-2011, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/ewsgi/src/gw_application.e b/library/server/ewsgi/src/gw_application.e similarity index 91% rename from library/ewsgi/src/gw_application.e rename to library/server/ewsgi/src/gw_application.e index 334d3456..28cdf494 100644 --- a/library/ewsgi/src/gw_application.e +++ b/library/server/ewsgi/src/gw_application.e @@ -11,6 +11,7 @@ deferred class feature -- Execution process (env: GW_ENVIRONMENT; a_input: GW_INPUT_STREAM; a_output: GW_OUTPUT_STREAM) + -- Process request with environment `env', and i/o streams `a_input' and `a_output' do execute (new_request_context (env, a_input, a_output)) end diff --git a/library/server/ewsgi/src/gw_connector.e b/library/server/ewsgi/src/gw_connector.e new file mode 100644 index 00000000..881a7e4c --- /dev/null +++ b/library/server/ewsgi/src/gw_connector.e @@ -0,0 +1,44 @@ +note + description: "Summary description for {GW_CONNECTOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + GW_CONNECTOR + +feature {NONE} -- Initialization + + make (a_app: like application) + do + application := a_app + initialize + end + + initialize + -- Initialize connector + do + end + +feature {NONE} -- Access + + application: GW_APPLICATION + -- Gateway Application + +feature -- Server + + launch + 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/ewsgi/src/gw_cookie.e b/library/server/ewsgi/src/gw_cookie.e similarity index 100% rename from library/ewsgi/src/gw_cookie.e rename to library/server/ewsgi/src/gw_cookie.e diff --git a/library/ewsgi/src/gw_environment_names.e b/library/server/ewsgi/src/gw_environment_names.e similarity index 100% rename from library/ewsgi/src/gw_environment_names.e rename to library/server/ewsgi/src/gw_environment_names.e diff --git a/library/server/ewsgi/src/gw_error.e b/library/server/ewsgi/src/gw_error.e new file mode 100644 index 00000000..3cc1caf8 --- /dev/null +++ b/library/server/ewsgi/src/gw_error.e @@ -0,0 +1,66 @@ +note + description: "Summary description for {GW_ERROR}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_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: "Copyright (c) 1984-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/ewsgi/src/implementation/gw_application_imp.e b/library/server/ewsgi/src/implementation/gw_application_imp.e new file mode 100644 index 00000000..1f1961cc --- /dev/null +++ b/library/server/ewsgi/src/implementation/gw_application_imp.e @@ -0,0 +1,50 @@ +note + description: "Summary description for {GW_APPLICATION_IMP} " + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class + GW_APPLICATION_IMP + +inherit + GW_APPLICATION + redefine + process + end + +feature -- Access + + request_count: INTEGER + -- Request count + +feature -- Execution + + process (env: GW_ENVIRONMENT; a_input: GW_INPUT_STREAM; a_output: GW_OUTPUT_STREAM) + -- Process request with environment `env', and i/o streams `a_input' and `a_output' + do + request_count := request_count + 1 + Precursor (env, a_input, a_output) + end + +feature -- Factory + + new_request_context (env: GW_ENVIRONMENT; a_input: GW_INPUT_STREAM; a_output: GW_OUTPUT_STREAM): GW_REQUEST_CONTEXT + do + create {GW_REQUEST_CONTEXT_IMP} Result.make (env, a_input, a_output) + Result.execution_variables.set_variable (request_count.out, "REQUEST_COUNT") + 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/ewsgi/src/implementation/gw_request_context_imp.e b/library/server/ewsgi/src/implementation/gw_request_context_imp.e new file mode 100644 index 00000000..cdd83630 --- /dev/null +++ b/library/server/ewsgi/src/implementation/gw_request_context_imp.e @@ -0,0 +1,818 @@ +note + description: "[ + Server request context of the httpd request + + You can create your own descendant of this class to + add/remove specific value or processing + + This object is created by {GW_APPLICATION}.new_request_context + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + GW_REQUEST_CONTEXT_IMP + +inherit + GW_REQUEST_CONTEXT + +create + make + +feature {NONE} -- Initialization + + make (env: GW_ENVIRONMENT; a_input: like input; a_output: like output) + require + env_attached: env /= Void + do + create error_handler.make + input := a_input + output := a_output + environment := env + content_length := env.content_length_value + create execution_variables.make (10) + create uploaded_files.make (0) + + raw_post_data_recorded := True + + initialize + analyze + end + + initialize + -- Specific initialization + local + p: INTEGER + dt: DATE_TIME + env: like environment + do + env := environment + --| Here one can set its own environment entries if needed + + --| do not use `force', to avoid overwriting existing variable + if attached env.request_uri as rq_uri then + p := rq_uri.index_of ('?', 1) + if p > 0 then + env.set_variable (rq_uri.substring (1, p-1), {GW_ENVIRONMENT_NAMES}.self) + else + env.set_variable (rq_uri, {GW_ENVIRONMENT_NAMES}.self) + end + end + if env.variable ({GW_ENVIRONMENT_NAMES}.request_time) = Void then + env.set_variable (date_time_utilities.unix_time_stamp (Void).out, {GW_ENVIRONMENT_NAMES}.request_time) + end + end + + analyze + -- Analyze context, set various attributes and validate values + do + extract_variables + end + +feature -- Access: Input/Output + + output: GW_OUTPUT_STREAM + -- Server output channel + + input: GW_INPUT_STREAM + -- Server input channel + +feature -- Status + + raw_post_data_recorded: BOOLEAN assign set_raw_post_data_recorded + -- Record RAW POST DATA in environment variables + -- 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: environment variables + + environment: GW_ENVIRONMENT + -- Environment variables + + content_length: INTEGER + -- Extracted Content-Length value + +feature -- Access: execution variables + + execution_variables: GW_EXECUTION_VARIABLES + -- Execution variables set by the application + +feature -- URL parameters + + parameters: GW_REQUEST_VARIABLES + local + vars: like internal_parameters + p,e: INTEGER + rq_uri: like environment.request_uri + s: detachable STRING + do + vars := internal_parameters + if vars = Void then + s := environment.query_string + if s = Void then + rq_uri := environment.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 + if s /= Void and then not s.is_empty then + create vars.make_from_urlencoded (s, True) + else + create vars.make (0) + end + internal_parameters := vars + end + Result := vars + end + +feature -- Form fields and related + + form_fields: GW_REQUEST_VARIABLES + local + vars: like internal_form_fields + s: STRING + n: INTEGER + l_type: detachable STRING + do + vars := internal_form_fields + if vars = Void then + n := content_length + if n > 0 then + l_type := environment.content_type + if + l_type /= Void and then + l_type.starts_with ({HTTP_CONSTANTS}.multipart_form) + then + create vars.make (5) + --| FIXME: optimization ... fetch the input data progressively, otherwise we might run out of memory ... + s := form_input_data (n) + analyze_multipart_form (l_type, s, vars) + else + s := form_input_data (n) + create vars.make_from_urlencoded (s, True) + end + if raw_post_data_recorded then + vars.add_variable (s, "RAW_POST_DATA") + end + else + create vars.make (0) + end + internal_form_fields := vars + end + Result := vars + end + + uploaded_files: HASH_TABLE [TUPLE [name: STRING; type: STRING; tmp_name: STRING; tmp_basename: STRING; error: INTEGER; size: INTEGER], 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 -- Cookies + + cookies_variables: HASH_TABLE [STRING, STRING] + -- Expanded cookies variable + local + l_cookies: like cookies + do + l_cookies := cookies + create Result.make (l_cookies.count) + from + l_cookies.start + until + l_cookies.after + loop + if attached l_cookies.item_for_iteration.variables as vars then + from + vars.start + until + vars.after + loop + Result.force (vars.item_for_iteration, vars.key_for_iteration) + vars.forth + end + else + check same_name: l_cookies.key_for_iteration.same_string (l_cookies.item_for_iteration.name) end + Result.force (l_cookies.item_for_iteration.value, l_cookies.key_for_iteration) + end + l_cookies.forth + end + end + + cookies: HASH_TABLE [GW_COOKIE, STRING] + -- Cookies Information + local + i,j,p,n: INTEGER + l_cookies: like internal_cookies + k,v: STRING + do + l_cookies := internal_cookies + if l_cookies = Void then + if attached environment_variable ({GW_ENVIRONMENT_NAMES}.http_cookie) as s then + create l_cookies.make (5) + 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.put (create {GW_COOKIE}.make (k,v), k) + end + end + else + create l_cookies.make (0) + end + internal_cookies := l_cookies + end + Result := l_cookies + end + +feature -- Query + +-- script_absolute_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) +-- else +-- --| Issue ?? +-- end +-- 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 +-- local +-- l_base_url: like script_url_base +-- i,m,n: INTEGER +-- l_rq_uri: like request_uri +-- do +-- l_base_url := script_url_base +-- if l_base_url = Void then +-- if attached environment.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 +-- script_url_base := l_base_url +-- end +-- Result := l_base_url + a_path +-- end + +-- script_url_base: detachable STRING +-- -- URL base of potential script + +feature -- Access environment information + + request_time: detachable DATE_TIME + -- Request time (UTC) + do + if + attached environment.variable ({GW_ENVIRONMENT_NAMES}.request_time) as t and then + t.is_integer_64 + then + Result := date_time_utilities.unix_time_stamp_to_date_time (t.to_integer_64) + end + end + +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 + + update_path_info (env: GW_ENVIRONMENT) + -- Fix and update PATH_INFO value if needed + local + l_path_info: STRING + do + l_path_info := env.path_info + --| Warning + --| on IIS: we might have PATH_INFO = /sample.exe/foo/bar + --| on apache: PATH_INFO = /foo/bar + --| So, we might need to check with SCRIPT_NAME and remove it on IIS + --| store original PATH_INFO in ORIG_PATH_INFO + if l_path_info.is_empty then + env.unset_orig_path_info + else + env.set_orig_path_info (l_path_info) + if attached env.script_name as l_script_name then + if l_path_info.starts_with (l_script_name) then + env.path_info := l_path_info.substring (l_script_name.count + 1 , l_path_info.count) + end + end + end + end + +feature -- Uploaded File Handling + + move_uploaded_file (a_filename: STRING; a_destination: STRING): BOOLEAN + -- Move uploaded file `a_filename' to `a_destination' + --| if this is not an uploaded file, do not move it. + local + f: RAW_FILE + do + if is_uploaded_file (a_filename) then + create f.make (a_filename) + if f.exists then + f.change_name (a_destination) + Result := True + end + end + end + + 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 l_files.item_for_iteration.tmp_name.same_string (a_filename) then + Result := True + end + l_files.forth + end + end + end + +feature {NONE} -- Temporary File handling + + delete_uploaded_file (a_filename: STRING) + -- Delete file `a_filename' + local + f: RAW_FILE + do + if is_uploaded_file (a_filename) then + create f.make (a_filename) + if f.exists and then f.is_writable then + f.delete + else + error_handler.add_custom_error (0, "Can not delete file", "Can not delete file %""+ a_filename +"%"") + end + else + error_handler.add_custom_error (0, "Not uploaded file", "This file %""+ a_filename +"%" is not an uploaded file.") + end + end + + save_uploaded_file (a_content: STRING; a_filename: STRING): detachable TUPLE [name: STRING; basename: STRING] + -- 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_filename) + 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 + f.open_write + f.put_string (a_content) + f.close + Result := [f.name, bn] + else + Result := Void + end + else + error_handler.add_custom_error (0, "Directory not writable", "Can not create file in directory %""+ dn +"%"") + end + else + Result := Void + 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_fields) + -- 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_fields) + -- 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 + 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 + if attached save_uploaded_file (l_content, l_filename) as l_saved_fn_info then + uploaded_files.force ([l_filename, l_content_type, l_saved_fn_info.name, l_saved_fn_info.basename, 0, l_content.count], l_name) + else + uploaded_files.force ([l_filename, l_content_type, "", "", -1, l_content.count], l_name) + end + else + vars_post.add_variable (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_parameters: detachable like parameters + -- cached value for `parameters' + + internal_form_fields: detachable like form_fields + -- cached value for `form_fields' + + internal_cookies: detachable like cookies + -- 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: GW_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 + + extract_variables + -- Extract relevant environment variables + local + s: detachable STRING + do + s := environment.request_uri + if s.is_empty then + report_bad_request_error ("Missing URI") + end + if not has_error then + s := environment.request_method + if s.is_empty then + report_bad_request_error ("Missing request method") + end + end + if not has_error then + s := environment.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 (environment) + end + end + +feature {NONE} -- Implementation: utilities + + date_time_utilities: HTTP_DATE_TIME_UTILITIES + -- Utilities classes related to date and time. + once + create Result + 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/ewsgi/src/gw_input_stream.e b/library/server/ewsgi/src/stream/gw_input_stream.e similarity index 100% rename from library/ewsgi/src/gw_input_stream.e rename to library/server/ewsgi/src/stream/gw_input_stream.e diff --git a/library/ewsgi/src/gw_output_stream.e b/library/server/ewsgi/src/stream/gw_output_stream.e similarity index 100% rename from library/ewsgi/src/gw_output_stream.e rename to library/server/ewsgi/src/stream/gw_output_stream.e diff --git a/library/server/libfcgi/README.txt b/library/server/libfcgi/README.txt new file mode 100644 index 00000000..046d354f --- /dev/null +++ b/library/server/libfcgi/README.txt @@ -0,0 +1,7 @@ +To compile your own binaries .lib and .dll on Windows +please get the source from + +https://github.com/EiffelSoftware/libfcgi + +git repository: + git clone https://github.com/EiffelSoftware/libfcgi.git \ No newline at end of file diff --git a/library/server/libfcgi/doc/Configuration_examples.txt b/library/server/libfcgi/doc/Configuration_examples.txt new file mode 100644 index 00000000..fcb3f1e4 --- /dev/null +++ b/library/server/libfcgi/doc/Configuration_examples.txt @@ -0,0 +1,50 @@ += How to configure FCGI = +== Apache2/Windows == +* in apache2/conf/httpd.conf add + LoadModule fcgid_module modules/mod_fcgid.so + +* and for instance, you can put the following code to test the tests/eiffelweb example + + + FcgidIdleTimeout 60 + FcgidBusyScanInterval 120 + FcgidProcessLifeTime 1600 + #7200 + FcgidMaxProcesses 5 + FcgidMaxProcessesPerClass 100 + FcgidMinProcessesPerClass 100 + FcgidConnectTimeout 8 + FcgidIOTimeout 3000 + FcgidBusyTimeout 3200 + FcgidPassHeader Authorization + + + alias /eiffelweb/ "c:/_dev/EiffelWebReloaded/library/fcgi/tests/EIFGENs/eiffelweb/W_code/" + + AddHandler fcgid-script .exe + Options Indexes FollowSymLinks ExecCGI + + Order allow,deny + Allow from all + + + + +== IIS/Windows == +* When you install IIS on Windows 7, you just need to enable to CGI module which also include the FastCGI module +* otherwise, have a look at http://www.iis.net/download/FastCGI and also http://learn.iis.net/page.aspx/375/set-up-fastcgi-for-php/ +* Then open the IIS Manager + Modules: to check you really have FastCGIModule + Handler Mappings and then "Add Module Mapping" + Request path: *.exe + Module: FastCgiModule + Executable (optional): c:\_dev\EiffelWebReloaded\library\fcgi\tests\EIFGENs\eiffelweb\W_code\eiffelweb.exe + Name: Eiffel Web Solution using FastCGI on IIS + + += Notes = +* The notes in this readme are very basic, mainly to test your executable. +* You will need to configure more precisely your httpd server to fulfill your needs + +== for execution == +* On Windows, be sure to have the libfcgi.dll in your path (or in same folder as executable) diff --git a/library/server/libfcgi/fcgi.ecf b/library/server/libfcgi/fcgi.ecf new file mode 100644 index 00000000..14784c26 --- /dev/null +++ b/library/server/libfcgi/fcgi.ecf @@ -0,0 +1,52 @@ + + + + + + /\.svn$ + /\.git$ + /EIFGENs$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + /linux$ + /fake$ + + + + + + /windows$ + /fake$ + + + + + + + diff --git a/library/server/libfcgi/implementation/fake/fcgi_imp.e b/library/server/libfcgi/implementation/fake/fcgi_imp.e new file mode 100644 index 00000000..fd4e3e56 --- /dev/null +++ b/library/server/libfcgi/implementation/fake/fcgi_imp.e @@ -0,0 +1,104 @@ +note + description: "Implementation for the FCGI_I interface" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class FCGI_IMP + +inherit + FCGI_I + +feature -- Access + + environ: POINTER + -- Get the (char**) environ variable from the DLL. + external + "C inline use %"fcgi_stdio.h%"" + alias + "return (char**) environ;" + end + +feature -- FCGI connection + + fcgi_listen: INTEGER + -- Listen to the FCGI input stream + -- Return 0 for successful calls, -1 otherwise. + do + -- Set state on first call to prevent looping indefinitely + if fcgi_has_run then + Result := -1 + else --if not is_interactive then + fcgi_has_run := True + end + end + + fcgi_has_run: BOOLEAN + -- For emulation only; Has fcgi_listen been called? + + fcgi_finish + -- Finish current request from HTTP server started from + -- the most recent call to `fcgi_accept'. + do + end + + set_fcgi_exit_status (v: INTEGER) + do + end + +feature -- FCGI output + + put_string (a_str: STRING) + -- Put `a_str' on the FastCGI stdout. + do + io.put_string (a_str) + end + +-- fcgi_printf (fmt: STRING; args: FINITE[ANY]) +-- -- Put args, formatted per 'fmt' on the FastCGI stdout. +-- do +-- apf.printf (fmt, args) +-- end + +feature -- FCGI Input + + read_from_stdin (n: INTEGER) + -- Read up to n bytes from stdin and store in input buffer + do + end + + copy_from_stdin (n: INTEGER; tf: FILE) + -- Read up to n bytes from stdin and write to given file + do + end + +feature -- Status + + buffer_contents: STRING + do + if attached private_input_buffer as buf then + Result := buf + else + Result := "" + end + end + + buffer_capacity: INTEGER + do + if attached private_input_buffer as bug then + Result := buf.capacity + end + end + +note + copyright: "Copyright (c) 1984-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/libfcgi/implementation/linux/fcgi_c_api.e b/library/server/libfcgi/implementation/linux/fcgi_c_api.e new file mode 100644 index 00000000..909bc652 --- /dev/null +++ b/library/server/libfcgi/implementation/linux/fcgi_c_api.e @@ -0,0 +1,97 @@ +note + description: "Wrappers around FastCGI C API." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + FCGI_C_API + +feature -- Connection + + accept: INTEGER + -- Accept a Fast CGI connection. + -- Return 0 for successful calls, -1 otherwise. + external + "C inline use %"fcgi_stdio.h%"" + alias + "return FCGI_Accept();" + end + + environ: POINTER + -- Get the (char**) environ variable from the DLL. + external + "C inline use %"fcgi_stdio.h%"" + alias + "return (char**) environ;" + end + + finish + -- Finished current request from HTTP server started from + -- the most recent call to `fcgi_accept'. + external + "C inline use %"fcgi_stdio.h%"" + alias + "FCGI_Finish();" + end + + set_exit_status (v: INTEGER) + -- Set the exit status for the most recent request + external + "C inline use %"fcgi_stdio.h%"" + alias + "FCGI_SetExitStatus($v);" + end + +feature -- Input + + read_content_into (a_buffer: POINTER; a_length: INTEGER): INTEGER + -- Read content stream into `a_buffer' but no more than `a_length' character. + external + "C inline use %"fcgi_stdio.h%"" + alias + "[ + { + size_t n; + if (! FCGI_feof(FCGI_stdin)) { + n = FCGI_fread($a_buffer, 1, $a_length, FCGI_stdin); + } else { + n = 0; + } + return n; + } + ]" + end + + gets (s: POINTER): POINTER + -- gets() reads a line from stdin into the buffer pointed to + -- by s until either a terminating newline or EOF, which it + -- replaces with '\0' + -- No check for buffer overrun is performed + external + "C inline use %"fcgi_stdio.h%"" + alias + "return FCGI_gets($s);" + end + +feature -- Output + + put_string (v: POINTER; n: INTEGER) + external + "C inline use %"fcgi_stdio.h%"" + alias + "FCGI_fwrite($v, 1, $n, FCGI_stdout);" + end + +note + copyright: "Copyright (c) 1984-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/libfcgi/implementation/linux/fcgi_imp.e b/library/server/libfcgi/implementation/linux/fcgi_imp.e new file mode 100644 index 00000000..f7dcb620 --- /dev/null +++ b/library/server/libfcgi/implementation/linux/fcgi_imp.e @@ -0,0 +1,183 @@ +note + description: "Implementation for the FCGI_I interface" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class FCGI_IMP + +inherit + FCGI_I + STRING_HANDLER + +feature {NONE} -- Initialization + + make + -- Initialize FCGI interface + do + create fcgi + end + + fcgi: FCGI_C_API + -- FastCGI C API primitives + + +feature -- Access + + fcgi_environ: POINTER + do + Result := fcgi.environ + end + +feature -- FCGI Connection + + fcgi_listen: INTEGER + -- Listen to the FCGI input stream + -- Return 0 for successful calls, -1 otherwise. + do + Result := {FCGI_C_API}.accept + end + + update_eif_environ + external + "C inline use " + alias + "[ + eif_environ = (char**) environ; + ]" + end + + fcgi_finish + -- Finish current request from HTTP server started from + -- the most recent call to `fcgi_accept'. + do + {FCGI_C_API}.finish + end + + set_fcgi_exit_status (v: INTEGER) + do + {FCGI_C_API}.set_exit_status (-2) + end + +feature -- FCGI output + + put_string (a_str: STRING) + -- Put `a_str' on the FastCGI stdout. + local + l_c_str: C_STRING + do + l_c_str := c_buffer + l_c_str.set_string (a_str) + {FCGI_C_API}.put_string (l_c_str.item, l_c_str.count) + end + +-- fcgi_printf (fmt: STRING; args: FINITE[ANY]) +-- -- Put args, formatted per 'fmt' on the FastCGI stdout. +-- local +-- l_c_str: C_STRING +-- do +-- create l_c_str.make (apf.aprintf (fmt, args)) +-- {FCGI_C_API}.put_string (l_c_str.item, l_c_str.count) +-- end + +feature -- FCGI Input + + copy_from_stdin (n: INTEGER; tf: FILE) + -- Read up to n bytes from stdin and write to given file + local + l_c_str: C_STRING + num, readsize, writecount: INTEGER + done: BOOLEAN + do + --put_trace ("copy_from_stdin, n=" +n.out) + readsize := n.min (K_input_bufsize) + --put_trace ("copy_from_stdin, readsize=" +readsize.out) + l_c_str := c_buffer + from + until done or writecount >= n + loop + num := {FCGI_C_API}.read_content_into (l_c_str.item, readsize) + --put_trace ("copy_from_stdin, num=" +num.out) + if num = 0 then + -- EOF + done := True + else + tf.put_managed_pointer (c_buffer.managed_data, 0, num) + writecount := writecount + num + end + end + end + +feature {NONE} -- Implementation: FCGI Input + + fill_pointer_from_stdin (p: POINTER; n: INTEGER): INTEGER + -- Read up to `n' bytes from stdin and store in pointer `p' + -- and return number of bytes read. + do + Result := {FCGI_C_API}.read_content_into (p, n) + end + +feature -- I/O Routines + +--RFO read_stdin_into (a_str: STRING) +--RFO -- Read a string from the `stdin' into `a_str'. +--RFO require +--RFO a_str_not_void: a_str /= Void +--RFO local +--RFO l_c_str: C_STRING +--RFO n: INTEGER +--RFO do +--RFO l_c_str := c_buffer +--RFO n := {FCGI_C_API}.read_content_into (l_c_str.item, l_c_str.capacity) +--RFO a_str.set_count (n) +--RFO l_c_str.read_substring_into (a_str, 1, n) +--RFO end + +--RFO read_string_into (a_str: STRING) +--RFO require +--RFO exists: a_str /= Void +--RFO local +--RFO l_c_str: C_STRING +--RFO p: POINTER +--RFO do +--RFO create l_c_str.make_empty (1024) +--RFO p := {FCGI_C_API}.gets (l_c_str.item) +--RFO-- if p /= default_pointer and p = l_c_str.item then +--RFO a_str.resize (l_c_str.count) +--RFO l_c_str.read_string_into (a_str) +--RFO-- else +--RFO-- put_error_line ("Bad pointer from gets") +--RFO-- end +--RFO end + +--RFO read_line +--RFO -- Read up to the next end of line, or end of input +--RFO -- Leave result in last_string +--RFO -- Newline character is absent from result +--RFO do +--RFO if last_string = Void then +--RFO create Result.make (K_input_bufsize) +--RFO else +--RFO last_string.wipe_out +--RFO end +--RFO-- if input_filename /= Void then +--RFO-- io.read_line +--RFO-- last_string.append (io.last_string) +--RFO-- else +--RFO read_string_into (last_string) +--RFO-- end +--RFO end + +note + copyright: "Copyright (c) 1984-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/libfcgi/implementation/windows/fcgi_c_api.e b/library/server/libfcgi/implementation/windows/fcgi_c_api.e new file mode 100644 index 00000000..efae2d8f --- /dev/null +++ b/library/server/libfcgi/implementation/windows/fcgi_c_api.e @@ -0,0 +1,136 @@ +note + description: "Wrappers around FastCGI C API." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + FCGI_C_API + +feature -- Connections + + accept: INTEGER + -- Accept a Fast CGI connection. + -- Return 0 for successful calls, -1 otherwise. + external + "dll libfcgi.dll signature (): EIF_INTEGER use fcgi_stdio.h " + alias + "FCGI_Accept" + end + + environ: POINTER + -- Get the (char**) environ variable from the DLL. + external + "dll libfcgi.dll signature (): EIF_POINTER use fcgi_stdio.h " + alias + "FCGI_Environ" + end + + finish + -- Finished current request from HTTP server started from + -- the most recent call to `accept'. + external + "dll libfcgi.dll signature () use fcgi_stdio.h " + alias + "FCGI_Finish" + end + + set_exit_status (v: INTEGER) + -- Set the exit status for the most recent request + external + "dll libfcgi.dll signature (EIF_INTEGER) use fcgi_stdio.h " + alias + "FCGI_SetExitStatus" + end + +feature -- Input + + fread (v: POINTER; a_size: INTEGER; n: INTEGER; fp: POINTER): INTEGER + -- FCGI_fread() read from input `fp' and put into `v' + external + "dll libfcgi.dll signature (EIF_POINTER, EIF_INTEGER, EIF_INTEGER, EIF_POINTER): EIF_INTEGER use fcgi_stdio.h " + alias + "FCGI_fread" + end + + feof (v: POINTER): INTEGER + -- FCGI_feof() + external + "dll libfcgi.dll signature (EIF_POINTER): EIF_INTEGER use fcgi_stdio.h " + alias + "FCGI_feof" + end + + read_content_into (a_buffer: POINTER; a_length: INTEGER): INTEGER + -- Read content stream into `a_buffer' but no more than `a_length' character. + local + i: INTEGER + l_stdin: POINTER + do + l_stdin := stdin + i := feof (l_stdin) + if i /= 0 then + Result := 0 + else + Result := fread(a_buffer, 1, a_length, l_stdin) + end + end + + gets (s: POINTER): POINTER + -- gets() reads a line from stdin into the buffer pointed to + -- by `s' until either a terminating newline or EOF, which it + -- replaces with '\0' + -- No check for buffer overrun is performed + external + "dll libfcgi.dll signature (EIF_POINTER): EIF_POINTER use fcgi_stdio.h " + alias + "FCGI_gets" + end + +feature -- Output + + put_string (v: POINTER; n: INTEGER) + local + i: INTEGER + do + i := fwrite (v, 1, n, stdout) + end + + fwrite (v: POINTER; a_size: INTEGER; n: INTEGER; fp: POINTER): INTEGER + -- FCGI_fwrite() ouput `v' to `fp' + external + "dll libfcgi.dll signature (EIF_POINTER, EIF_INTEGER, EIF_INTEGER, EIF_POINTER): EIF_INTEGER use fcgi_stdio.h " + alias + "FCGI_fwrite" + end + +feature -- Access + + stdout: POINTER + -- FCGI_stdout() return pointer on output FCGI_FILE + external + "C inline use %"fcgi_stdio.h%"" + alias + "FCGI_stdout" + end + + stdin: POINTER + -- FCGI_stdin() return pointer on input FCGI_FILE + external + "C inline use %"fcgi_stdio.h%"" + alias + "FCGI_stdin" + end + +note + copyright: "Copyright (c) 1984-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/libfcgi/implementation/windows/fcgi_imp.e b/library/server/libfcgi/implementation/windows/fcgi_imp.e new file mode 100644 index 00000000..8c35d3f5 --- /dev/null +++ b/library/server/libfcgi/implementation/windows/fcgi_imp.e @@ -0,0 +1,267 @@ +note + description: "Implementation for the FCGI_I interface" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class FCGI_IMP + +inherit + FCGI_I + +feature {NONE} -- Initialization + + make + -- Initialize FCGI interface + do + create fcgi + end + + fcgi: FCGI_C_API + -- FastCGI C API primitives + +feature -- Access + + fcgi_environ: POINTER + do + Result := fcgi.environ + end + +-- updated_environ_variables: HASH_TABLE [STRING, STRING] +-- local +---- n, l_size, +-- i: INTEGER +-- p, v, null: POINTER +-- do +---- update_eif_environ +---- Result := starting_environment_variables +-- +---- p := environ_strings_pointer ($n) +---- from +---- i := 1 +---- l_size := 0 +---- create Result.make (n) +---- until +---- i > n +---- loop +---- create s.make_from_c (p.plus (l_size)) +---- l_size := l_size + s.count + 1 +---- if attached separated_variables (s) as t then +---- Result.force (t.value, t.key) +---- end +---- i := i + 1 +---- end +-- +-- p := fcgi.environ +-- create Result.make (50) +-- if p /= null then +-- from +-- i := 0 +-- v := fcgi_i_th_environ (i,p) +-- until +-- v = null +-- loop +-- if attached separated_variables (create {STRING}.make_from_c (v)) as t then +-- Result.force (t.value, t.key) +-- end +-- i := i + 1 +-- v := fcgi_i_th_environ (i,p) +-- end +-- end +-- end +-- +-- fcgi_i_th_environ (i: INTEGER; p: POINTER): POINTER +-- -- Environment variable at `i'-th position of `p'. +-- require +-- i_valid: i >=0 +-- external +-- "C inline use " +-- alias +-- "[ +-- return ((char **)$p)[$i]; +-- ]" +-- end + +feature -- FCGI connection + + fcgi_listen: INTEGER + -- Listen to the FCGI input stream + -- Return 0 for successful calls, -1 otherwise. + do + Result := fcgi.accept + end + +-- update_eif_environ +-- external +-- "C inline use " +-- alias +-- "[ +-- #ifdef EIF_WINDOWS +-- #ifndef GetEnvironmentStringsA +-- extern LPVOID WINAPI GetEnvironmentStringsA(void); +-- #endif +-- +-- eif_environ = (char**) GetEnvironmentStringsA(); +-- #endif +-- ]" +-- end + + fcgi_finish + -- Finish current request from HTTP server started from + -- the most recent call to `fcgi_accept'. + do + fcgi.finish + end + + set_fcgi_exit_status (v: INTEGER) + do + fcgi.set_exit_status (-2) + end + +feature -- FCGI output + + put_string (a_str: STRING) + -- Put `a_str' on the FastCGI stdout. + local + l_c_str: C_STRING + do + l_c_str := c_buffer + l_c_str.set_string (a_str) + fcgi.put_string (l_c_str.item, l_c_str.count) + end + +feature -- FCGI input + + copy_from_stdin (n: INTEGER; f: FILE) + -- Read up to n bytes from stdin and write to given file + local + l_c_str: C_STRING + num, readsize, writecount: INTEGER + done: BOOLEAN + l_fcgi: like fcgi + do + --put_trace ("copy_from_stdin, n=" +n.out) + readsize := n.min (K_input_bufsize) + --put_trace ("copy_from_stdin, readsize=" +readsize.out) + l_c_str := c_buffer + from + l_fcgi := fcgi + until done or writecount >= n + loop + num := l_fcgi.read_content_into (l_c_str.item, readsize) + --put_trace ("copy_from_stdin, num=" +num.out) + if num = 0 then + -- EOF + done := True + else + f.put_managed_pointer (c_buffer.managed_data, 0, num) + writecount := writecount + num + end + end + end + +feature {NONE} -- Implementation: FCGI Input + + fill_pointer_from_stdin (p: POINTER; n: INTEGER): INTEGER + -- Read up to `n' bytes from stdin and store in pointer `p' + -- and return number of bytes read. + do + Result := fcgi.read_content_into (p, n) + end + +feature -- I/O Routines + +--RFO read_stdin_into (a_str: STRING) +--RFO -- Read a string from the `stdin' into `a_str'. +--RFO require +--RFO a_str_not_void: a_str /= Void +--RFO local +--RFO l_c_str: C_STRING +--RFO n: INTEGER +--RFO do +--RFO l_c_str := c_buffer +--RFO n := fcgi.read_content_into (l_c_str.item, l_c_str.capacity) +--RFO a_str.set_count (n) +--RFO l_c_str.read_substring_into (a_str, 1, n) +--RFO end + +--RFO read_string_into (a_str: STRING) +--RFO require +--RFO exists: a_str /= Void +--RFO local +--RFO l_c_str: C_STRING +--RFO p: POINTER +--RFO do +--RFO create l_c_str.make_empty (1024) +--RFO p := fcgi.gets (l_c_str.item) +--RFO-- if p /= default_pointer and p = l_c_str.item then +--RFO a_str.resize (l_c_str.count) +--RFO l_c_str.read_string_into (a_str) +--RFO-- else +--RFO-- put_error_line ("Bad pointer from gets") +--RFO-- end +--RFO end + + +--RFO read_line +--RFO -- Read up to the next end of line, or end of input +--RFO -- Leave result in last_string +--RFO -- Newline character is absent from result +--RFO do +--RFO if last_string = Void then +--RFO create Result.make (K_input_bufsize) +--RFO else +--RFO last_string.wipe_out +--RFO end +--RFO-- if input_filename /= Void then +--RFO-- io.read_line +--RFO-- last_string.append (io.last_string) +--RFO-- else +--RFO read_string_into (last_string) +--RFO-- end +--RFO end + + + +feature {NONE} -- Implementation: environment + +-- environ_strings_pointer (p_nb: TYPED_POINTER [INTEGER]): POINTER +-- -- Environment variable strings returned by `GetEnvironmentStringsA' +-- -- `p_nb' return the count of environment variables. +-- external +-- "C inline use " +-- alias +-- "[ +-- #ifdef EIF_WINDOWS +-- #ifndef GetEnvironmentStringsA +-- extern LPVOID WINAPI GetEnvironmentStringsA(void); +-- #endif +-- +-- int cnt = 0; +-- LPSTR vars = GetEnvironmentStringsA(); +-- char** p = (char**) vars; +-- +-- for (; *vars; vars++) { +-- while (*vars) { vars++; } +-- cnt++; +-- } +-- +-- *$p_nb = cnt; +-- return (EIF_POINTER) p; +-- #endif +-- ]" +-- end + + +note + copyright: "Copyright (c) 1984-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/libfcgi/interface/fcgi.e b/library/server/libfcgi/interface/fcgi.e new file mode 100644 index 00000000..4f56f56a --- /dev/null +++ b/library/server/libfcgi/interface/fcgi.e @@ -0,0 +1,26 @@ +note + description: "Interface to FCGI C library" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class FCGI + +inherit + FCGI_IMP + +create + make + +note + copyright: "Copyright (c) 1984-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/libfcgi/interface/fcgi_i.e b/library/server/libfcgi/interface/fcgi_i.e new file mode 100644 index 00000000..7010e48b --- /dev/null +++ b/library/server/libfcgi/interface/fcgi_i.e @@ -0,0 +1,236 @@ +note + description: "Abstract interface to FCGI C library" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class FCGI_I + +inherit + STRING_HANDLER + +feature {NONE} -- Initialization + + make + -- Initialize FCGI interface + deferred + end + +feature -- Access + + updated_environ_variables: HASH_TABLE [STRING, STRING] + local + i: INTEGER + p, v, null: POINTER + do + p := fcgi_environ + create Result.make (50) + if p /= null then + from + i := 0 + v := fcgi_i_th_environ (i,p) + until + v = null + loop + if attached separated_variables (create {STRING}.make_from_c (v)) as t then + Result.force (t.value, t.key) + end + i := i + 1 + v := fcgi_i_th_environ (i,p) + end + end + end + +feature -- FCGI interface + + fcgi_listen: INTEGER + -- Listen to the FCGI input stream + -- Return 0 for successful calls, -1 otherwise. + deferred + end + + fcgi_environ: POINTER + -- Get the (char**) environ variable from the DLL. + deferred + end + + fcgi_finish + -- Finish current request from HTTP server started from + -- the most recent call to `fcgi_accept'. + deferred + end + + set_fcgi_exit_status (v: INTEGER) + deferred + end + +feature -- Status + + is_interactive: BOOLEAN + -- Is execution interactive? (for debugging) + do + end + +feature -- Input + + fill_string_from_stdin (s: STRING; n: INTEGER) + -- Read up to `n' bytes from stdin and store in string `s' + local + new_count: INTEGER + str_area: ANY + do + s.grow (n) + str_area := s.area + new_count := fill_pointer_from_stdin ($str_area, n) + s.set_count (new_count) + end + + read_from_stdin (n: INTEGER) + -- Read up to n bytes from stdin and store in input buffer + require + small_enough: n <= buffer_capacity + local + l_c_str: C_STRING + l_count: INTEGER + do + last_read_is_empty_ref.set_item (False) + l_c_str := c_buffer + l_count := fill_pointer_from_stdin (l_c_str.item, n) + last_read_count_ref.set_item (l_count) + if l_count <= 0 then + last_read_is_empty_ref.set_item (True) + end + end + + fill_pointer_from_stdin (p: POINTER; n: INTEGER): INTEGER + -- Read up to `n' bytes from stdin and store in pointer `p' + -- and return number of bytes read. + deferred + end + + copy_from_stdin (n: INTEGER; f: FILE) + -- Read up to n bytes from stdin and write to given file + require +-- small_enough: n <= buffer_capacity + file_exists: f /= Void + file_open: f.is_open_write or f.is_open_append + deferred + end + +feature -- Output + + put_string (a_str: STRING) + -- Put `a_str' on the FastCGI stdout. + require + a_str_not_void: a_str /= Void + deferred + end + +feature -- Implementation + + buffer_contents: STRING + local + n: like last_read_count + do + n := last_read_count + create Result.make (n) + Result.set_count (n) + c_buffer.read_substring_into (Result, 1, n) + end + + buffer_capacity: INTEGER + do + Result := c_buffer.capacity + end + +--RFO last_string: STRING +--RFO once +--RFO create Result.make (K_input_bufsize) +--RFO end + + last_read_count: INTEGER + do + Result := last_read_count_ref.item + end + + last_read_is_empty: BOOLEAN + do + Result := last_read_is_empty_ref.item + end + +feature {NONE} -- Shared buffer + + c_buffer: C_STRING + -- Buffer for Eiffel to C and C to Eiffel string conversions. + once + create Result.make_empty (K_input_bufsize) + ensure + c_buffer_not_void: Result /= Void + end + + +feature {NONE} -- Constants + + last_read_count_ref: INTEGER_REF + once + create Result + end + + last_read_is_empty_ref: BOOLEAN_REF + once + create Result + end + + K_input_bufsize: INTEGER = 1024_000 + +feature {NONE} -- Implementation: Environment + + fcgi_i_th_environ (i: INTEGER; p: POINTER): POINTER + -- Environment variable at `i'-th position of `p'. + require + i_valid: i >=0 + external + "C inline use " + alias + "return ((char **)$p)[$i];" + end + + separated_variables (a_var: STRING): detachable TUPLE [value: STRING; key: STRING] + -- Given an environment variable `a_var' in form of "key=value", + -- return separated key and value. + -- Return Void if `a_var' is in incorrect format. + require + a_var_attached: a_var /= Void + local + i, j: INTEGER + done: BOOLEAN + do + j := a_var.count + from + i := 1 + until + i > j or done + loop + if a_var.item (i) = '=' then + done := True + else + i := i + 1 + end + end + if i > 1 and then i < j then + Result := [a_var.substring (i + 1, j), a_var.substring (1, i - 1)] + end + end + +note + copyright: "Copyright (c) 1984-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/libfcgi/libfcgi-safe.ecf b/library/server/libfcgi/libfcgi-safe.ecf new file mode 100644 index 00000000..d5a9e54f --- /dev/null +++ b/library/server/libfcgi/libfcgi-safe.ecf @@ -0,0 +1,52 @@ + + + + + + /\.svn$ + /\.git$ + /EIFGENs$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + /linux$ + /fake$ + + + + + + /windows$ + /fake$ + + + + + + + diff --git a/library/server/libfcgi/libfcgi.ecf b/library/server/libfcgi/libfcgi.ecf new file mode 100644 index 00000000..d69396be --- /dev/null +++ b/library/server/libfcgi/libfcgi.ecf @@ -0,0 +1,52 @@ + + + + + + /\.svn$ + /\.git$ + /EIFGENs$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + /linux$ + /fake$ + + + + + + /windows$ + /fake$ + + + + + + + diff --git a/library/server/libfcgi/license.lic b/library/server/libfcgi/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/server/libfcgi/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/server/libfcgi/spec/include/libfcgi/fastcgi.h b/library/server/libfcgi/spec/include/libfcgi/fastcgi.h new file mode 100644 index 00000000..d5b54686 --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fastcgi.h @@ -0,0 +1,136 @@ +/* + * fastcgi.h -- + * + * Defines for the FastCGI protocol. + * + * + * Copyright (c) 1995-1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fastcgi.h,v 1.1.1.1 1997/09/16 15:36:32 stanleyg Exp $ + */ + +#ifndef _FASTCGI_H +#define _FASTCGI_H + +/* + * Listening socket file number + */ +#define FCGI_LISTENSOCK_FILENO 0 + +typedef struct { + unsigned char version; + unsigned char type; + unsigned char requestIdB1; + unsigned char requestIdB0; + unsigned char contentLengthB1; + unsigned char contentLengthB0; + unsigned char paddingLength; + unsigned char reserved; +} FCGI_Header; + +#define FCGI_MAX_LENGTH 0xffff + +/* + * Number of bytes in a FCGI_Header. Future versions of the protocol + * will not reduce this number. + */ +#define FCGI_HEADER_LEN 8 + +/* + * Value for version component of FCGI_Header + */ +#define FCGI_VERSION_1 1 + +/* + * Values for type component of FCGI_Header + */ +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +/* + * Value for requestId component of FCGI_Header + */ +#define FCGI_NULL_REQUEST_ID 0 + + +typedef struct { + unsigned char roleB1; + unsigned char roleB0; + unsigned char flags; + unsigned char reserved[5]; +} FCGI_BeginRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_BeginRequestBody body; +} FCGI_BeginRequestRecord; + +/* + * Mask for flags component of FCGI_BeginRequestBody + */ +#define FCGI_KEEP_CONN 1 + +/* + * Values for role component of FCGI_BeginRequestBody + */ +#define FCGI_RESPONDER 1 +#define FCGI_AUTHORIZER 2 +#define FCGI_FILTER 3 + + +typedef struct { + unsigned char appStatusB3; + unsigned char appStatusB2; + unsigned char appStatusB1; + unsigned char appStatusB0; + unsigned char protocolStatus; + unsigned char reserved[3]; +} FCGI_EndRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_EndRequestBody body; +} FCGI_EndRequestRecord; + +/* + * Values for protocolStatus component of FCGI_EndRequestBody + */ +#define FCGI_REQUEST_COMPLETE 0 +#define FCGI_CANT_MPX_CONN 1 +#define FCGI_OVERLOADED 2 +#define FCGI_UNKNOWN_ROLE 3 + + +/* + * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records + */ +#define FCGI_MAX_CONNS "FCGI_MAX_CONNS" +#define FCGI_MAX_REQS "FCGI_MAX_REQS" +#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" + + +typedef struct { + unsigned char type; + unsigned char reserved[7]; +} FCGI_UnknownTypeBody; + +typedef struct { + FCGI_Header header; + FCGI_UnknownTypeBody body; +} FCGI_UnknownTypeRecord; + +#endif /* _FASTCGI_H */ + diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgi_config.h b/library/server/libfcgi/spec/include/libfcgi/fcgi_config.h new file mode 100644 index 00000000..c59cda80 --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgi_config.h @@ -0,0 +1,39 @@ +/* + * Copied to fcgi_config.h when building on WinNT without cygwin, + * i.e. configure is not run. See fcgi_config.h.in for details. + */ + +#define HAVE_FPOS 1 +#define HAVE_LIMITS_H 1 +#define HAVE_STREAMBUF_CHAR_TYPE 1 +#define HAVE_STRERROR 1 +#undef HAVE_ARPA_INET_H +#undef HAVE_DLFCN_H +#undef HAVE_FILENO_PROTO +#undef HAVE_INTTYPES_H +#undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF +#undef HAVE_LIBNSL +#undef HAVE_LIBSOCKET +#undef HAVE_MEMORY_H +#undef HAVE_NETDB_H +#undef HAVE_NETINET_IN_H +#undef HAVE_PTHREAD +#undef HAVE_SOCKADDR_UN_SUN_LEN +#undef HAVE_SOCKLEN +#undef HAVE_STDINT_H +#undef HAVE_STDLIB_H +#undef HAVE_STRING_H +#undef HAVE_STRINGS_H +#undef HAVE_SYS_PARAM_H +#undef HAVE_SYS_SOCKET_H +#undef HAVE_SYS_STAT_H +#undef HAVE_SYS_TIME_H +#undef HAVE_SYS_TYPES_H +#undef HAVE_UNISTD_H +#undef HAVE_VA_ARG_LONG_DOUBLE_BUG +#undef PTHREAD_CREATE_JOINABLE +#undef STDC_HEADERS +#undef USE_LOCKING +#undef const +#undef inline +#undef ssize_t diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgi_config_x86.h b/library/server/libfcgi/spec/include/libfcgi/fcgi_config_x86.h new file mode 100644 index 00000000..c59cda80 --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgi_config_x86.h @@ -0,0 +1,39 @@ +/* + * Copied to fcgi_config.h when building on WinNT without cygwin, + * i.e. configure is not run. See fcgi_config.h.in for details. + */ + +#define HAVE_FPOS 1 +#define HAVE_LIMITS_H 1 +#define HAVE_STREAMBUF_CHAR_TYPE 1 +#define HAVE_STRERROR 1 +#undef HAVE_ARPA_INET_H +#undef HAVE_DLFCN_H +#undef HAVE_FILENO_PROTO +#undef HAVE_INTTYPES_H +#undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF +#undef HAVE_LIBNSL +#undef HAVE_LIBSOCKET +#undef HAVE_MEMORY_H +#undef HAVE_NETDB_H +#undef HAVE_NETINET_IN_H +#undef HAVE_PTHREAD +#undef HAVE_SOCKADDR_UN_SUN_LEN +#undef HAVE_SOCKLEN +#undef HAVE_STDINT_H +#undef HAVE_STDLIB_H +#undef HAVE_STRING_H +#undef HAVE_STRINGS_H +#undef HAVE_SYS_PARAM_H +#undef HAVE_SYS_SOCKET_H +#undef HAVE_SYS_STAT_H +#undef HAVE_SYS_TIME_H +#undef HAVE_SYS_TYPES_H +#undef HAVE_UNISTD_H +#undef HAVE_VA_ARG_LONG_DOUBLE_BUG +#undef PTHREAD_CREATE_JOINABLE +#undef STDC_HEADERS +#undef USE_LOCKING +#undef const +#undef inline +#undef ssize_t diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgi_stdio.h b/library/server/libfcgi/spec/include/libfcgi/fcgi_stdio.h new file mode 100644 index 00000000..7deae531 --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgi_stdio.h @@ -0,0 +1,246 @@ +/* + * fcgi_stdio.h -- + * + * FastCGI-stdio compatibility package + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgi_stdio.h,v 1.5 2001/06/22 13:21:15 robs Exp $ + */ + +#ifndef _FCGI_STDIO +#define _FCGI_STDIO 1 + +#include +#include +#include "fcgiapp.h" + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +/* + * Wrapper type for FILE + */ + +typedef struct { + FILE *stdio_stream; + FCGX_Stream *fcgx_stream; +} FCGI_FILE; + +/* + * The four new functions and two new macros + */ + +DLLAPI int FCGI_Accept(void); +DLLAPI char** FCGI_Environ(void); +DLLAPI void FCGI_Finish(void); +DLLAPI int FCGI_StartFilterData(void); +DLLAPI void FCGI_SetExitStatus(int status); + +#define FCGI_ToFILE(fcgi_file) (fcgi_file->stdio_stream) +#define FCGI_ToFcgiStream(fcgi_file) (fcgi_file->fcgx_stream) + +/* + * Wrapper stdin, stdout, and stderr variables, set up by FCGI_Accept() + */ + +DLLAPI extern FCGI_FILE _fcgi_sF[]; +#define FCGI_stdin (&_fcgi_sF[0]) +#define FCGI_stdout (&_fcgi_sF[1]) +#define FCGI_stderr (&_fcgi_sF[2]) + +/* + * Wrapper function prototypes, grouped according to sections + * of Harbison & Steele, "C: A Reference Manual," fourth edition, + * Prentice-Hall, 1995. + */ + +DLLAPI void FCGI_perror(const char *str); + +DLLAPI FCGI_FILE *FCGI_fopen(const char *path, const char *mode); +DLLAPI int FCGI_fclose(FCGI_FILE *fp); +DLLAPI int FCGI_fflush(FCGI_FILE *fp); +DLLAPI FCGI_FILE *FCGI_freopen(const char *path, const char *mode, FCGI_FILE *fp); + +DLLAPI int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size); +DLLAPI void FCGI_setbuf(FCGI_FILE *fp, char *buf); + +DLLAPI int FCGI_fseek(FCGI_FILE *fp, long offset, int whence); +DLLAPI int FCGI_ftell(FCGI_FILE *fp); +DLLAPI void FCGI_rewind(FCGI_FILE *fp); +#ifdef HAVE_FPOS +DLLAPI int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos); +DLLAPI int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos); +#endif +DLLAPI int FCGI_fgetc(FCGI_FILE *fp); +DLLAPI int FCGI_getchar(void); +DLLAPI int FCGI_ungetc(int c, FCGI_FILE *fp); + +DLLAPI char *FCGI_fgets(char *str, int size, FCGI_FILE *fp); +DLLAPI char *FCGI_gets(char *str); + +/* + * Not yet implemented + * + * int FCGI_fscanf(FCGI_FILE *fp, const char *format, ...); + * int FCGI_scanf(const char *format, ...); + * + */ + +DLLAPI int FCGI_fputc(int c, FCGI_FILE *fp); +DLLAPI int FCGI_putchar(int c); + +DLLAPI int FCGI_fputs(const char *str, FCGI_FILE *fp); +DLLAPI int FCGI_puts(const char *str); + +DLLAPI int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...); +DLLAPI int FCGI_printf(const char *format, ...); + +DLLAPI int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap); +DLLAPI int FCGI_vprintf(const char *format, va_list ap); + +DLLAPI size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp); +DLLAPI size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp); + +DLLAPI int FCGI_feof(FCGI_FILE *fp); +DLLAPI int FCGI_ferror(FCGI_FILE *fp); +DLLAPI void FCGI_clearerr(FCGI_FILE *fp); + +DLLAPI FCGI_FILE *FCGI_tmpfile(void); + +DLLAPI int FCGI_fileno(FCGI_FILE *fp); +DLLAPI FCGI_FILE *FCGI_fdopen(int fd, const char *mode); +DLLAPI FCGI_FILE *FCGI_popen(const char *cmd, const char *type); +DLLAPI int FCGI_pclose(FCGI_FILE *); + +/* + * The remaining definitions are for application programs, + * not for fcgi_stdio.c + */ + +#ifndef NO_FCGI_DEFINES + +/* + * Replace standard types, variables, and functions with FastCGI wrappers. + * Use undef in case a macro is already defined. + */ + +#undef FILE +#define FILE FCGI_FILE + +#undef stdin +#define stdin FCGI_stdin +#undef stdout +#define stdout FCGI_stdout +#undef stderr +#define stderr FCGI_stderr + +#undef perror +#define perror FCGI_perror + +#undef fopen +#define fopen FCGI_fopen +#undef fclose +#define fclose FCGI_fclose +#undef fflush +#define fflush FCGI_fflush +#undef freopen +#define freopen FCGI_freopen + +#undef setvbuf +#define setvbuf FCGI_setvbuf +#undef setbuf +#define setbuf FCGI_setbuf + +#undef fseek +#define fseek FCGI_fseek +#undef ftell +#define ftell FCGI_ftell +#undef rewind +#define rewind FCGI_rewind +#undef fgetpos +#define fgetpos FCGI_fgetpos +#undef fsetpos +#define fsetpos FCGI_fsetpos + +#undef fgetc +#define fgetc FCGI_fgetc +#undef getc +#define getc FCGI_fgetc +#undef getchar +#define getchar FCGI_getchar +#undef ungetc +#define ungetc FCGI_ungetc + +#undef fgets +#define fgets FCGI_fgets +#undef gets +#define gets FCGI_gets + +#undef fputc +#define fputc FCGI_fputc +#undef putc +#define putc FCGI_fputc +#undef putchar +#define putchar FCGI_putchar + +#undef fputs +#define fputs FCGI_fputs +#undef puts +#define puts FCGI_puts + +#undef fprintf +#define fprintf FCGI_fprintf +#undef printf +#define printf FCGI_printf + +#undef vfprintf +#define vfprintf FCGI_vfprintf +#undef vprintf +#define vprintf FCGI_vprintf + +#undef fread +#define fread FCGI_fread +#undef fwrite +#define fwrite FCGI_fwrite + +#undef feof +#define feof FCGI_feof +#undef ferror +#define ferror FCGI_ferror +#undef clearerr +#define clearerr FCGI_clearerr + +#undef tmpfile +#define tmpfile FCGI_tmpfile + +#undef fileno +#define fileno FCGI_fileno +#undef fdopen +#define fdopen FCGI_fdopen +#undef popen +#define popen FCGI_popen +#undef pclose +#define pclose FCGI_pclose + +#endif /* NO_FCGI_DEFINES */ + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGI_STDIO */ + diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgiapp.h b/library/server/libfcgi/spec/include/libfcgi/fcgiapp.h new file mode 100644 index 00000000..d7236f6f --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgiapp.h @@ -0,0 +1,622 @@ +/* + * fcgiapp.h -- + * + * Definitions for FastCGI application server programs + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgiapp.h,v 1.12 2001/11/21 21:10:11 robs Exp $ + */ + +#ifndef _FCGIAPP_H +#define _FCGIAPP_H + +/* Hack to see if we are building TCL - TCL needs varargs not stdarg */ +#ifndef TCL_LIBRARY +#include +#else +#include +#endif + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +/* + * Error codes. Assigned to avoid conflict with EOF and errno(2). + */ +#define FCGX_UNSUPPORTED_VERSION -2 +#define FCGX_PROTOCOL_ERROR -3 +#define FCGX_PARAMS_ERROR -4 +#define FCGX_CALL_SEQ_ERROR -5 + +/* + * This structure defines the state of a FastCGI stream. + * Streams are modeled after the FILE type defined in stdio.h. + * (We wouldn't need our own if platform vendors provided a + * standard way to subclass theirs.) + * The state of a stream is private and should only be accessed + * by the procedures defined below. + */ +typedef struct FCGX_Stream { + unsigned char *rdNext; /* reader: first valid byte + * writer: equals stop */ + unsigned char *wrNext; /* writer: first free byte + * reader: equals stop */ + unsigned char *stop; /* reader: last valid byte + 1 + * writer: last free byte + 1 */ + unsigned char *stopUnget; /* reader: first byte of current buffer + * fragment, for ungetc + * writer: undefined */ + int isReader; + int isClosed; + int wasFCloseCalled; + int FCGI_errno; /* error status */ + void (*fillBuffProc) (struct FCGX_Stream *stream); + void (*emptyBuffProc) (struct FCGX_Stream *stream, int doClose); + void *data; +} FCGX_Stream; + +/* + * An environment (as defined by environ(7)): A NULL-terminated array + * of strings, each string having the form name=value. + */ +typedef char **FCGX_ParamArray; + +/* + * FCGX_Request Flags + * + * Setting FCGI_FAIL_ACCEPT_ON_INTR prevents FCGX_Accept() from + * restarting upon being interrupted. + */ +#define FCGI_FAIL_ACCEPT_ON_INTR 1 + +/* + * FCGX_Request -- State associated with a request. + * + * Its exposed for API simplicity, I expect parts of it to change! + */ +typedef struct FCGX_Request { + int requestId; /* valid if isBeginProcessed */ + int role; + FCGX_Stream *in; + FCGX_Stream *out; + FCGX_Stream *err; + char **envp; + + /* Don't use anything below here */ + + struct Params *paramsPtr; + int ipcFd; /* < 0 means no connection */ + int isBeginProcessed; /* FCGI_BEGIN_REQUEST seen */ + int keepConnection; /* don't close ipcFd at end of request */ + int appStatus; + int nWriters; /* number of open writers (0..2) */ + int flags; + int listen_sock; +} FCGX_Request; + + +/* + *====================================================================== + * Control + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_IsCGI -- + * + * Returns TRUE iff this process appears to be a CGI process + * rather than a FastCGI process. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_IsCGI(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Init -- + * + * Initialize the FCGX library. Call in multi-threaded apps + * before calling FCGX_Accept_r(). + * + * Returns 0 upon success. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Init(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_OpenSocket -- + * + * Create a FastCGI listen socket. + * + * path is the Unix domain socket (named pipe for WinNT), or a colon + * followed by a port number. e.g. "/tmp/fastcgi/mysocket", ":5000" + * + * backlog is the listen queue depth used in the listen() call. + * + * Returns the socket's file descriptor or -1 on error. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_OpenSocket(const char *path, int backlog); + +/* + *---------------------------------------------------------------------- + * + * FCGX_InitRequest -- + * + * Initialize a FCGX_Request for use with FCGX_Accept_r(). + * + * sock is a file descriptor returned by FCGX_OpenSocket() or 0 (default). + * The only supported flag at this time is FCGI_FAIL_ON_INTR. + * + * Returns 0 upon success. + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_InitRequest(FCGX_Request *request, int sock, int flags); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept_r -- + * + * Accept a new request (multi-thread safe). Be sure to call + * FCGX_Init() first. + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + * DON'T use the FCGX_Request, its structure WILL change. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Accept_r(FCGX_Request *request); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish_r -- + * + * Finish the request (multi-thread safe). + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Finish_r(FCGX_Request *request); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Free -- + * + * Free the memory and, if close is true, + * IPC FD associated with the request (multi-thread safe). + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Free(FCGX_Request * request, int close); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept -- + * + * Accept a new request (NOT multi-thread safe). + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Accept( + FCGX_Stream **in, + FCGX_Stream **out, + FCGX_Stream **err, + FCGX_ParamArray *envp); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish -- + * + * Finish the current request (NOT multi-thread safe). + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Finish(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_StartFilterData -- + * + * stream is an input stream for a FCGI_FILTER request. + * stream is positioned at EOF on FCGI_STDIN. + * Repositions stream to the start of FCGI_DATA. + * If the preconditions are not met (e.g. FCGI_STDIN has not + * been read to EOF) sets the stream error code to + * FCGX_CALL_SEQ_ERROR. + * + * Results: + * 0 for a normal return, < 0 for error + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_StartFilterData(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_SetExitStatus -- + * + * Sets the exit status for stream's request. The exit status + * is the status code the request would have exited with, had + * the request been run as a CGI program. You can call + * SetExitStatus several times during a request; the last call + * before the request ends determines the value. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_SetExitStatus(int status, FCGX_Stream *stream); + +/* + *====================================================================== + * Parameters + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetParam -- obtain value of FCGI parameter in environment + * + * + * Results: + * Value bound to name, NULL if name not present in the + * environment envp. Caller must not mutate the result + * or retain it past the end of this request. + * + *---------------------------------------------------------------------- + */ +DLLAPI char *FCGX_GetParam(const char *name, FCGX_ParamArray envp); + +/* + *====================================================================== + * Readers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetChar -- + * + * Reads a byte from the input stream and returns it. + * + * Results: + * The byte, or EOF (-1) if the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetChar(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_UnGetChar -- + * + * Pushes back the character c onto the input stream. One + * character of pushback is guaranteed once a character + * has been read. No pushback is possible for EOF. + * + * Results: + * Returns c if the pushback succeeded, EOF if not. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_UnGetChar(int c, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetStr -- + * + * Reads up to n consecutive bytes from the input stream + * into the character array str. Performs no interpretation + * of the input bytes. + * + * Results: + * Number of bytes read. If result is smaller than n, + * the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetStr(char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetLine -- + * + * Reads up to n-1 consecutive bytes from the input stream + * into the character array str. Stops before n-1 bytes + * have been read if '\n' or EOF is read. The terminating '\n' + * is copied to str. After copying the last byte into str, + * stores a '\0' terminator. + * + * Results: + * NULL if EOF is the first thing read from the input stream, + * str otherwise. + * + *---------------------------------------------------------------------- + */ +DLLAPI char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_HasSeenEOF -- + * + * Returns EOF if end-of-file has been detected while reading + * from stream; otherwise returns 0. + * + * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately + * following FCGX_GetChar(s) may return EOF. This function, like + * the standard C stdio function feof, does not provide the + * ability to peek ahead. + * + * Results: + * EOF if end-of-file has been detected, 0 if not. + * + *---------------------------------------------------------------------- + */ + +DLLAPI int FCGX_HasSeenEOF(FCGX_Stream *stream); + +/* + *====================================================================== + * Writers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutChar -- + * + * Writes a byte to the output stream. + * + * Results: + * The byte, or EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutChar(int c, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutStr -- + * + * Writes n consecutive bytes from the character array str + * into the output stream. Performs no interpretation + * of the output bytes. + * + * Results: + * Number of bytes written (n) for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutS -- + * + * Writes a null-terminated character string to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutS(const char *str, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FPrintF, FCGX_VFPrintF -- + * + * Performs printf-style output formatting and writes the results + * to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...); + +DLLAPI int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FFlush -- + * + * Flushes any buffered output. + * + * Server-push is a legitimate application of FCGX_FFlush. + * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept + * does it implicitly. Calling FCGX_FFlush in non-push applications + * results in extra writes and therefore reduces performance. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FFlush(FCGX_Stream *stream); + +/* + *====================================================================== + * Both Readers and Writers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_FClose -- + * + * Closes the stream. For writers, flushes any buffered + * output. + * + * Close is not a very useful operation since FCGX_Accept + * does it implicitly. Closing the out stream before the + * err stream results in an extra write if there's nothing + * in the err stream, and therefore reduces performance. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FClose(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetError -- + * + * Return the stream error code. 0 means no error, > 0 + * is an errno(2) error, < 0 is an FastCGI error. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetError(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_ClearError -- + * + * Clear the stream error code and end-of-file indication. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_ClearError(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_CreateWriter -- + * + * Create a FCGX_Stream (used by cgi-fcgi). This shouldn't + * be needed by a FastCGI applictaion. + * + *---------------------------------------------------------------------- + */ +DLLAPI FCGX_Stream *FCGX_CreateWriter( + int socket, + int requestId, + int bufflen, + int streamType); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FreeStream -- + * + * Free a FCGX_Stream (used by cgi-fcgi). This shouldn't + * be needed by a FastCGI applictaion. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_FreeStream(FCGX_Stream **stream); + +/* ---------------------------------------------------------------------- + * + * Prevent the lib from accepting any new requests. Signal handler safe. + * + * ---------------------------------------------------------------------- + */ +DLLAPI void FCGX_ShutdownPending(void); + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGIAPP_H */ diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgimisc.h b/library/server/libfcgi/spec/include/libfcgi/fcgimisc.h new file mode 100644 index 00000000..0464455f --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgimisc.h @@ -0,0 +1,38 @@ +/* + * fcgimisc.h -- + * + * Miscellaneous definitions + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgimisc.h,v 1.3 2001/06/18 14:25:47 robs Exp $ + */ + +#ifndef _FCGIMISC_H +#define _FCGIMISC_H + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef ASSERT +#define ASSERT(assertion) assert(assertion) +#endif + +#endif /* _FCGIMISC_H */ diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgio.h b/library/server/libfcgi/spec/include/libfcgi/fcgio.h new file mode 100644 index 00000000..20d222ab --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgio.h @@ -0,0 +1,151 @@ +// +// Provides support for FastCGI via C++ iostreams. +// +// $Id: fcgio.h,v 1.15 2002/02/25 13:16:11 robs Exp $ +// +// This work is based on routines written by George Feinberg. They +// have been mostly re-written and extensively changed by +// Michael Richards. +// +// Rewritten again with bug fixes and numerous enhancements by +// Michael Shell. +// +// And rewritten again by Rob Saccoccio. +// +// Special Thanks to Dietmar Kuehl for his help and the numerous custom +// streambuf examples on his web site. +// +// Copyright (c) 2000 Tux the Linux Penguin +// Copyright (c) 2001 Rob Saccoccio and Chelsea Networks +// +// You are free to use this software without charge or royalty +// as long as this notice is not removed or altered, and recognition +// is given to the author(s) +// +// This code is offered as-is without any warranty either expressed or +// implied; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. If it breaks, you get to keep +// both halves. + +#ifndef FCGIO_H +#define FCGIO_H + +#include + +#include "fcgiapp.h" + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +#if ! HAVE_STREAMBUF_CHAR_TYPE +typedef char char_type; +#endif + +/* + * fcgi_streambuf + */ +class DLLAPI fcgi_streambuf : public std::streambuf +{ +public: + + // Note that if no buf is assigned (the default), iostream methods + // such as peek(), unget() and putback() will fail. If a buf is + // assigned, I/O is a bit less effecient and output streams will + // have to be flushed (or the streambuf destroyed) before the next + // call to "accept". + fcgi_streambuf(FCGX_Stream * fcgx, char * buf, int len); + + fcgi_streambuf(char_type * buf, std::streamsize len); + + fcgi_streambuf(FCGX_Stream * fcgx = 0); + + ~fcgi_streambuf(void); + + int attach(FCGX_Stream * fcgx); + +protected: + + // Consume the put area (if buffered) and c (if c is not EOF). + virtual int overflow(int); + + // Flush the put area (if buffered) and the FCGX buffer to the client. + virtual int sync(); + + // Remove and return the current character. + virtual int uflow(); + + // Fill the get area (if buffered) and return the current character. + virtual int underflow(); + + // Use a buffer. The only reasons that a buffer would be useful is + // to support the use of the unget()/putback() or seek() methods. Using + // a buffer will result in less efficient I/O. Note: the underlying + // FastCGI library (FCGX) maintains its own input and output buffers. + virtual std::streambuf * setbuf(char_type * buf, std::streamsize len); + + virtual std::streamsize xsgetn(char_type * s, std::streamsize n); + virtual std::streamsize xsputn(const char_type * s, std::streamsize n); + +private: + + FCGX_Stream * fcgx; + + // buf is just handy to have around + char_type * buf; + + // this isn't kept by the base class + std::streamsize bufsize; + + void init(FCGX_Stream * fcgx, char_type * buf, std::streamsize bufsize); + + void reset(void); +}; + +/* + * fcgi_istream - deprecated + */ +class DLLAPI fcgi_istream : public std::istream +{ +public: + + // deprecated + fcgi_istream(FCGX_Stream * fcgx = 0); + + // deprecated + ~fcgi_istream(void) {} + + // deprecated + virtual void attach(FCGX_Stream * fcgx); + +private: + + fcgi_streambuf fcgi_strmbuf; +}; + +/* + * fcgi_ostream - deprecated + */ +class DLLAPI fcgi_ostream : public std::ostream +{ +public: + + // deprecated + fcgi_ostream(FCGX_Stream * fcgx = 0); + + // deprecated + ~fcgi_ostream(void) {} + + // deprecated + virtual void attach(FCGX_Stream *fcgx); + +private: + + fcgi_streambuf fcgi_strmbuf; +}; + +#endif /* FCGIO_H */ diff --git a/library/server/libfcgi/spec/include/libfcgi/fcgios.h b/library/server/libfcgi/spec/include/libfcgi/fcgios.h new file mode 100644 index 00000000..de7c3c7c --- /dev/null +++ b/library/server/libfcgi/spec/include/libfcgi/fcgios.h @@ -0,0 +1,130 @@ +/* + * fcgios.h -- + * + * Description of file. + * + * + * Copyright (c) 1996 Open Market, Inc. + * All rights reserved. + * + * This file contains proprietary and confidential information and + * remains the unpublished property of Open Market, Inc. Use, + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + * + * Bill Snapper + * snapper@openmarket.com + */ +#ifndef _FCGIOS_H +#define _FCGIOS_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +#include "fcgi_config.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#ifdef _WIN32 +#define OS_Errno GetLastError() +#define OS_SetErrno(err) SetLastError(err) +#ifndef O_NONBLOCK +#define O_NONBLOCK 0x0004 /* no delay */ +#endif +#else /* !_WIN32 */ +#define OS_Errno errno +#define OS_SetErrno(err) errno = (err) +#endif /* !_WIN32 */ + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + + +/* This is the initializer for a "struct timeval" used in a select() call + * right after a new request is accept()ed to determine readablity. Its + * a drop-dead timer. Its only used for AF_UNIX sockets (not TCP sockets). + * Its a workaround for a kernel bug in Linux 2.0.x and SCO Unixware. + * Making this as small as possible, yet remain reliable would be best. + * 2 seconds is very conservative. 0,0 is not reliable. The shorter the + * timeout, the faster request processing will recover. The longer the + * timeout, the more likely this application being "busy" will cause other + * requests to abort and cause more dead sockets that need this timeout. */ +#define READABLE_UNIX_FD_DROP_DEAD_TIMEVAL 2,0 + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#ifndef X_OK +#define X_OK 0x01 +#endif + +#ifndef _CLIENTDATA +# if defined(__STDC__) || defined(__cplusplus) + typedef void *ClientData; +# else + typedef int *ClientData; +# endif /* __STDC__ */ +#define _CLIENTDATA +#endif + +typedef void (*OS_AsyncProc) (ClientData clientData, int len); + +DLLAPI int OS_LibInit(int stdioFds[3]); +DLLAPI void OS_LibShutdown(void); +DLLAPI int OS_CreateLocalIpcFd(const char *bindPath, int backlog); +DLLAPI int OS_FcgiConnect(char *bindPath); +DLLAPI int OS_Read(int fd, char * buf, size_t len); +DLLAPI int OS_Write(int fd, char * buf, size_t len); +DLLAPI int OS_SpawnChild(char *execPath, int listenFd); +DLLAPI int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, + ClientData clientData); +DLLAPI int OS_AsyncRead(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData); +DLLAPI int OS_AsyncWrite(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData); +DLLAPI int OS_Close(int fd); +DLLAPI int OS_CloseRead(int fd); +DLLAPI int OS_DoIo(struct timeval *tmo); +DLLAPI int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs); +DLLAPI int OS_IpcClose(int ipcFd); +DLLAPI int OS_IsFcgi(int sock); +DLLAPI void OS_SetFlags(int fd, int flags); + +DLLAPI void OS_ShutdownPending(void); + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGIOS_H */ diff --git a/library/server/libfcgi/spec/lib/win64/msc/libfcgi.dll b/library/server/libfcgi/spec/lib/win64/msc/libfcgi.dll new file mode 100644 index 0000000000000000000000000000000000000000..6b18c88f16aa50ecc0b936ff819559d6fb26cf09 GIT binary patch literal 51200 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

i^~+I+ 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 J{{BZt;2);6WQhO( literal 0 HcmV?d00001 diff --git a/library/server/libfcgi/spec/lib/win64/msc/libfcgi.lib b/library/server/libfcgi/spec/lib/win64/msc/libfcgi.lib new file mode 100644 index 0000000000000000000000000000000000000000..839cda3f7123e43265e605d0e130ff7e675b21b9 GIT binary patch literal 27710 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 literal 0 HcmV?d00001 diff --git a/library/server/libfcgi/spec/lib/windows/msc/libfcgi.dll b/library/server/libfcgi/spec/lib/windows/msc/libfcgi.dll new file mode 100644 index 0000000000000000000000000000000000000000..83d69a06251f5bd0116bfc8d92cabaae29e183d6 GIT binary patch literal 42496 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 literal 0 HcmV?d00001 diff --git a/library/server/libfcgi/tests/apache2.conf b/library/server/libfcgi/tests/apache2.conf new file mode 100644 index 00000000..5d9f3700 --- /dev/null +++ b/library/server/libfcgi/tests/apache2.conf @@ -0,0 +1,64 @@ + + ServerAdmin webmaster@localhost + + DocumentRoot /var/www + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + ErrorLog ${APACHE_LOG_DIR}/error.log + + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + + CustomLog ${APACHE_LOG_DIR}/access.log combined + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + +# FcgidIdleTimeout 600 +# FcgidBusyScanInterval 120 +# FcgidProcessLifeTime 0 +# #7200 +# FcgidMaxProcesses 1000 +# FcgidMaxProcessesPerClass 100 +# FcgidMinProcessesPerClass 100 +# FcgidConnectTimeout 8 +# FcgidIOTimeout 60 +# FcgidBusyTimeout 1200 + +alias /eiffelweb/ "/home/jfiat/_dev/EiffelWebReloaded/library/fcgi/tests/EIFGENs/eiffelweb/W_code/" + +AddHandler fcgid-script .ews +Options Indexes FollowSymLinks ExecCGI +# Customize the next two directives for your requirements. +Order allow,deny +Allow from all + + + + + diff --git a/library/server/libfcgi/tests/application_root.e b/library/server/libfcgi/tests/application_root.e new file mode 100644 index 00000000..336f899c --- /dev/null +++ b/library/server/libfcgi/tests/application_root.e @@ -0,0 +1,80 @@ +note + description : "Objects that ..." + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION_ROOT + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + local + res: INTEGER + nb: INTEGER + do + initialize + from + res := fcgi.fcgi_listen + until + res < 0 + loop + nb := nb + 1 + fcgi.put_string (header ("FCGI Eiffel Application")) + + fcgi.put_string ("

Hello FCGI Eiffel Application

%N") + fcgi.put_string ("Request number " + nb.out + "
%N") + + fcgi.put_string ("
    Environment variables%N") + print_environment_variables (fcgi.updated_environ_variables) + fcgi.put_string ("
") + fcgi.put_string (footer) + + res := fcgi.fcgi_listen + end + end + +feature -- Access + + header (a_title: STRING): STRING + do + Result := "Content-type: text/html%R%N" + Result.append ("%R%N") + Result.append ("%N") + Result.append ("" + a_title + "") + Result.append ("%N") + end + + footer: STRING + do + Result := "%N%N" + end + + print_environment_variables (vars: HASH_TABLE [STRING, STRING]) + local + do + from + vars.start + until + vars.after + loop + fcgi.put_string ("
  • " + vars.key_for_iteration + " = " + vars.item_for_iteration + "
  • %N") + vars.forth + end + end + +feature {NONE} -- Implementation + + initialize + do + create fcgi.make + end + + fcgi: FCGI + +end diff --git a/library/server/libfcgi/tests/eiffelweb.ecf b/library/server/libfcgi/tests/eiffelweb.ecf new file mode 100644 index 00000000..7ce530ca --- /dev/null +++ b/library/server/libfcgi/tests/eiffelweb.ecf @@ -0,0 +1,16 @@ + + + + + + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + diff --git a/library/text/encoder/encoder-safe.ecf b/library/text/encoder/encoder-safe.ecf new file mode 100644 index 00000000..24ceb5c2 --- /dev/null +++ b/library/text/encoder/encoder-safe.ecf @@ -0,0 +1,35 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + /tests$ + + + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + diff --git a/library/text/encoder/encoder.ecf b/library/text/encoder/encoder.ecf new file mode 100644 index 00000000..5ba35276 --- /dev/null +++ b/library/text/encoder/encoder.ecf @@ -0,0 +1,35 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + /tests$ + + + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + diff --git a/library/text/encoder/license.lic b/library/text/encoder/license.lic new file mode 100644 index 00000000..c929225f --- /dev/null +++ b/library/text/encoder/license.lic @@ -0,0 +1 @@ +reference:forum2 diff --git a/library/text/encoder/src/base64.e b/library/text/encoder/src/base64.e new file mode 100644 index 00000000..821139de --- /dev/null +++ b/library/text/encoder/src/base64.e @@ -0,0 +1,218 @@ +note + description: "Summary description for {BASE64}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + BASE64 + +inherit + ENCODER [STRING_8, STRING_8] + redefine + valid_encoded_string + end + +feature -- Access + + name: STRING = "base64" + +feature -- Status report + + has_error: BOOLEAN + + valid_encoded_string (v: STRING): BOOLEAN + do + Result := Precursor (v) and then + (v.is_empty or v.count >= 4) + end + +feature -- base64 encoder + + encoded_string (s: STRING): STRING_8 + -- base64 encoded value of `s'. + local + i,n: INTEGER + c: INTEGER + f: SPECIAL [BOOLEAN] + base64chars: STRING_8 + do + has_error := False + base64chars := character_map + from + n := s.count + i := (8 * n) \\ 6 + if i > 0 then + create f.make_filled (False, 8 * n + (6 - i)) + else + create f.make_filled (False, 8 * n) + end + i := 0 + until + i > n - 1 + loop + c := s.item (i + 1).code + f[8 * i + 0] := c.bit_test(7) + f[8 * i + 1] := c.bit_test(6) + f[8 * i + 2] := c.bit_test(5) + f[8 * i + 3] := c.bit_test(4) + f[8 * i + 4] := c.bit_test(3) + f[8 * i + 5] := c.bit_test(2) + f[8 * i + 6] := c.bit_test(1) + f[8 * i + 7] := c.bit_test(0) + i := i + 1 + end + from + i := 0 + n := f.count + create Result.make (n // 6) + until + i > n - 1 + loop + c := 0 + if f[i + 0] then c := c + 0x20 end + if f[i + 1] then c := c + 0x10 end + if f[i + 2] then c := c + 0x8 end + if f[i + 3] then c := c + 0x4 end + if f[i + 4] then c := c + 0x2 end + if f[i + 5] then c := c + 0x1 end + Result.extend (base64chars.item (c + 1)) + i := i + 6 + end + + i := s.count \\ 3 + if i > 0 then + from until i > 2 loop + Result.extend ('=') + i := i + 1 + end + end + end + +feature -- Decoder + + decoded_string (v: STRING): STRING + -- base64 decoded value of `s'. + local + byte_count: INTEGER + pos, n: INTEGER + byte1, byte2, byte3, byte4, tmp1, tmp2: INTEGER + done: BOOLEAN + base64chars: STRING_8 + c: CHARACTER + do + has_error := False + base64chars := character_map + n := v.count + create Result.make (n) + + from + pos := 0 + invariant + n = v.count + until + (pos >= n) or done + loop + byte_count := 0 + + pos := next_encoded_character_position (v, pos) + if pos <= n then + byte1 := base64chars.index_of (v[pos], 1) - 1 + byte_count := byte_count + 1 + + pos := next_encoded_character_position (v, pos) + if pos <= n then + byte2 := base64chars.index_of (v[pos], 1) - 1 + byte_count := byte_count + 1 + + pos := next_encoded_character_position (v, pos) + if pos <= n then + c := v[pos] + if c /= '=' then + byte3 := base64chars.index_of (c, 1) - 1 + byte_count := byte_count + 1 + end + + pos := next_encoded_character_position (v, pos) + if pos <= n then + c := v[pos] + if c /= '=' then + byte4 := base64chars.index_of (c, 1) - 1 + byte_count := byte_count + 1 + end + end + end + end + end +-- pos := pos + byte_count + + done := byte_count < 4 + + if byte_count > 1 then + tmp1 := byte1.bit_shift_left (2) & 0xff + tmp2 := byte2.bit_shift_right (4) & 0x03 + Result.extend ((tmp1 | tmp2).to_character_8) + if byte_count > 2 then + tmp1 := byte2.bit_shift_left (4) & 0xff + tmp2 := byte3.bit_shift_right (2) & 0x0f + Result.extend ((tmp1 | tmp2).to_character_8) + if byte_count > 3 then + Result.extend( + ((byte4 | byte3.bit_shift_left(6))& 0xff).to_character_8) + end + end + end + end + end + + next_encoded_character_position (v: STRING; from_pos: INTEGER): INTEGER + -- Next encoded character position from `v' starting after `from_pos' index. + -- Result over `v.count' denodes no remaining decodable position + --| Mainly to handle base64 encoded text on multiple line + --| thus we just skip %N, %R and eventually all blanks + require + v_attached: v /= Void + valid_from_pos: v.valid_index (from_pos + 1) + local + n: INTEGER + l_map: like character_map + do + l_map := character_map + from + Result := from_pos + 1 + n := v.count + until + in_character_map (v[Result]) or Result > n + loop + Result := Result + 1 + end + ensure + result_after_from_pos: Result > from_pos + end + + in_character_map (c: CHARACTER): BOOLEAN + -- Is a character map element? + do + inspect c + when 'A' .. 'Z', 'a' .. 'z', '0'..'9', '+', '/', '=' then + Result := True + else + end + end + +feature {NONE} -- Constants + + character_map: STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + +note + copyright: "Copyright (c) 1984-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/text/encoder/src/encoder.e b/library/text/encoder/src/encoder.e new file mode 100644 index 00000000..52cfa047 --- /dev/null +++ b/library/text/encoder/src/encoder.e @@ -0,0 +1,73 @@ +note + description: "Summary description for {ENCODER}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +deferred class + ENCODER [U -> STRING_GENERAL, E -> STRING_GENERAL] --| U:unencoded type, E:encoded type + +feature -- Access + + name: STRING + -- Encoding name. + deferred + end + +feature -- Status report + + has_error: BOOLEAN + -- Error occurred + deferred + end + +feature -- Assertion helpers + + valid_unencoded_string (s: U): BOOLEAN + -- Is `s' a valid unencoded string ? + do + Result := s /= Void + end + + valid_encoded_string (v: E): BOOLEAN + -- Is `v' a valid encoded string ? + do + Result := v /= Void + end + +feature -- Encoder + + encoded_string (s: U): E + -- Encoded value of `s'. + require + valid_unencoded_string: valid_unencoded_string (s) + deferred + ensure + unchanged: s ~ (old s) + valid_encoded_string: valid_encoded_string (Result) + end + +feature -- Decoder + + decoded_string (v: E): U + -- Decoded value of `v'. + require + valid_encoded_string: valid_encoded_string (v) + deferred + ensure + unchanged: v ~ (old v) + valid_unencoded_string: valid_unencoded_string (Result) + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/src/html_encoder.e b/library/text/encoder/src/html_encoder.e new file mode 100644 index 00000000..d3a409aa --- /dev/null +++ b/library/text/encoder/src/html_encoder.e @@ -0,0 +1,267 @@ +note + description: "[ + Summary description for {HTML_ENCODER}. + + see: http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + HTML_ENCODER + +inherit + ENCODER [STRING_32, STRING_8] + + PLATFORM + export + {NONE} all + end + +feature -- Access + + name: STRING = "HTML-encoded" + +feature -- Status report + + has_error: BOOLEAN + +feature -- Encoder + + encoded_string (s: STRING_32): STRING_8 + -- HTML-encoded value of `s'. + local + i, n: INTEGER + uc: CHARACTER_32 + c: CHARACTER_8 + do + has_error := False + create Result.make (s.count + s.count // 10) + n := s.count + from i := 1 until i > n loop + uc := s.item (i) + if uc.is_character_8 then + c := uc.to_character_8 + inspect c + when '%"' then Result.append_string (""") + when '&' then Result.append_string ("&") + when '%'' then Result.append_string ("'") + when '<' then Result.append_string ("<") + when '>' then Result.append_string (">") + else + Result.extend (c) + end + else + Result.append ("&#") + Result.append (uc.code.out) + Result.extend (';') + end + i := i + 1 + end + end + +feature -- Decoder + + decoded_string (v: STRING_8): STRING_32 + -- The HTML-encoded equivalent of the given string + local + i, n: INTEGER + c: CHARACTER + cl_i: CELL [INTEGER] + do + n := v.count + create Result.make (n) + create cl_i.put (0) + from i := 1 until i > n loop + c := v.item (i) + if c = '&' then + cl_i.replace (i) + Result.append_string (next_entity (v, cl_i)) + i := cl_i.item + else + Result.append_character (c.to_character_32) + i := i + 1 + end + end + end + +feature {NONE} -- Implementation: decoder + + next_entity (v: STRING_8; cl_i: CELL [INTEGER]): STRING_32 + -- Return next entity value + -- move index + local + i: INTEGER + c: CHARACTER + is_char: BOOLEAN + is_hexa: BOOLEAN + s: STRING_32 + do + i := cl_i.item + create s.make_empty + i := i + 1 + c := v[i] + if c = '#' then + is_char := True + i := i + 1 + c := v[i] + if c = 'x' then + is_hexa := True + i := i + 1 + c := v[i] + end + end + if is_char then + if is_hexa then + from + until + not c.is_hexa_digit or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + else + from + until + not c.is_digit or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + end + else + from + until + not valid_entity_character (c) or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + end + if c = ';' then + if is_char then + if is_hexa then + -- not yet implemented + s.prepend_character ('x') + s.prepend_character ('#') + s.prepend_character ('&') + s.append_character (';') + Result := s + elseif s.is_integer then + create Result.make (1) + Result.append_code (s.to_natural_32) + else + s.prepend_character ('&') + s.append_character (';') + Result := s + end + else + resolve_entity (s) + Result := s + end + cl_i.replace (i + 1) + else + cl_i.replace (cl_i.item + 1) + s.prepend_character ('&') + has_error := True -- ("Invalid entity syntax " + s) + Result := s + end + end + + resolve_entity (s: STRING_32) + -- Resolve `s' as an entity + --| Hardcoding the xml entities " & ' < and > + require + s_attached: s /= Void + local + l_resolved: BOOLEAN + do + inspect s[1].as_lower + when 'a' then + if + s.count = 3 and then + s[2].as_lower = 'm' and then + s[3].as_lower = 'p' + then -- & + l_resolved := True + s.wipe_out + s.append_character ('&') + elseif -- ' + s.count = 4 and then + s[2].as_lower = 'p' and then + s[3].as_lower = 'o' and then + s[4].as_lower = 's' + then + l_resolved := True + s.wipe_out + s.append_character ('%'') + end + when 'q' then + if + s.count = 4 and then + s[2].as_lower = 'u' and then + s[3].as_lower = 'o' and then + s[4].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('%"') + end + when 'l' then + if + s.count = 2 and then + s[2].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('<') + end + when 'g' then + if + s.count = 2 and then + s[2].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('>') + end + else + end + if not l_resolved then + s.prepend_character ('&') + s.append_character (';') + end + end + + valid_entity_character (c: CHARACTER): BOOLEAN + -- Is `c' a valid character in html entity value? + --| such as & + do + inspect + c + when 'a'..'z' then + Result := True + when 'A'..'Z' then + Result := True + when '0'..'9' then + Result := True + else + end + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/src/url_encoder.e b/library/text/encoder/src/url_encoder.e new file mode 100644 index 00000000..63b1af79 --- /dev/null +++ b/library/text/encoder/src/url_encoder.e @@ -0,0 +1,321 @@ +note + description: "Summary description for {URL_ENCODER}." + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + URL_ENCODER + +inherit + ENCODER [STRING_32, STRING_8] + + PLATFORM + export + {NONE} all + end + +feature -- Access + + name: STRING = "URL-encoded" + +feature -- Status report + + has_error: BOOLEAN + +feature -- Encoder + + encoded_string (s: STRING_32): STRING_8 + -- URL-encoded value of `s'. + local + i, n: INTEGER + uc: CHARACTER_32 + c: CHARACTER_8 + do + has_error := False + create Result.make (s.count + s.count // 10) + n := s.count + from i := 1 until i > n loop + uc := s.item (i) + if uc.is_character_8 then + c := uc.to_character_8 + inspect c + when + 'A' .. 'Z', + 'a' .. 'z', '0' .. '9', + '.', '-', '~', '_' + then + Result.extend (c) + when ' ' then + Result.extend ('+') + else + Result.append (url_encoded_char (uc)) + end + else + Result.append (url_encoded_char (uc)) + end + i := i + 1 + end + end + +feature {NONE} -- encoder character + + url_encoded_char (uc: CHARACTER_32): STRING_8 + do + create Result.make (3) + if uc.is_character_8 then + Result.extend ('%%') + Result.append (uc.code.to_hex_string) + from + until + Result.count < 2 or else Result[2] /= '0' + loop + Result.remove (2) + end + else + has_error := True --| Non-ascii escape not currently supported + end + ensure + exists: Result /= Void + end + +feature -- Decoder + + decoded_string (v: STRING_8): STRING_32 + -- The URL-encoded equivalent of the given string + local + i, n: INTEGER + c: CHARACTER + pr: CELL [INTEGER] + do + n := v.count + create Result.make (n) + from i := 1 + until i > n + loop + c := v.item (i) + inspect c + when '+' then + Result.append_character ({CHARACTER_32}' ') + when '%%' then + -- An escaped character ? + if i = n then + Result.append_character (c.to_character_32) + else + create pr.put (i) + Result.append (url_decoded_char (v, pr)) + i := pr.item + end + else + Result.append_character (c.to_character_32) + end + i := i + 1 + end + end + +feature {NONE} -- decoded character + + url_decoded_char (buf: STRING_8; posr: CELL [INTEGER]): STRING_32 + -- Character(s) resulting from decoding the URL-encoded string + require + stream_exists: buf /= Void + posr_exists: posr /= Void + valid_start: posr.item <= buf.count + local + c: CHARACTER + i, n, nb: INTEGER + not_a_digit: BOOLEAN + ascii_pos, ival: INTEGER + pos: INTEGER + do + --| pos is index in stream of escape character ('%') + pos := posr.item + create Result.make (4) + if buf.item (pos + 1) = 'u' then + -- An escaped Unicode (ucs2) value, from ECMA scripts + -- Has the form: %u where is the UCS value + -- of the character (two byte integer, one to 4 chars + -- after escape sequence). + -- UTF-8 result can be 1 to 4 characters + n := buf.count + from i := pos + 2 + until (i > n) or not_a_digit + loop + c := buf.item (i) + if c.is_hexa_digit then + ival := ival * 16 + if c.is_digit then + ival := ival + (c |-| '0') + else + ival := ival + (c.upper |-| 'A') + 10 + end + i := i + 1 + else + not_a_digit := True + end + end + posr.replace (i) + -- ival is now UCS2 value; needs conversion to UTF8 + Result.append_code (ival.as_natural_32) + nb := utf8_bytes_in_sequence (buf, pos) + else + -- ASCII char? + ascii_pos := hex_to_integer_32 (buf.substring (pos+1, pos+2)) + if ascii_pos >= 0x80 and ascii_pos <= 0xff then + -- Might be improperly escaped + Result.append_code (ascii_pos.as_natural_32) + posr.replace (pos + 2) + else + Result.append_code (ascii_pos.as_natural_32) + posr.replace (pos + 2) + end + end + ensure + exists: Result /= Void + end + +feature {NONE} -- UTF8 + + utf8_bytes_in_sequence (s: STRING_8; spos: INTEGER): INTEGER + -- If the given character is a legal first byte element in a + -- utf8 byte sequence (aka character), then return the number + -- of bytes in that sequence + -- Result of zero means it's not a utf8 first byte + require + exists: s /= Void + long_enough: s.count >= spos + do + Result := bytes_in_utf8_char (s.item (spos)) + end + + bytes_in_utf8_char (v: CHARACTER_8): INTEGER + -- If the given byte a legal first byte element in a utf8 sequence, + -- then the number of bytes in that character + -- Zero denotes an error, i.e. not a legal UTF8 char + -- + -- The first byte of a UTF8 encodes the length + local + c: NATURAL_8 + do + c := v.code.to_natural_8 + Result := 1 -- 7 bit ASCII + if (c & 0x80) /= 0 then + -- Hi bit means not ASCII + Result := 0 + if (c & 0xe0) = 0xc0 then + -- If we see a first byte as b110xxxxx + -- then we expect a two-byte character + Result := 2 + elseif (c & 0xf0) = 0xe0 then + -- If we see a first byte as b1110xxxx + -- then we expect a three-byte character + Result := 3 + elseif (c & 0xf8) = 0xf0 then + -- If we see a first byte as b11110xxx + -- then we expect a four-byte character + Result := 4 + elseif (c & 0xfc) = 0xf8 then + -- If we see a first byte as b111110xx + -- then we expect a five-byte character + Result := 5 + elseif (c & 0xfe) = 0xfc then + -- If we see a first byte as b1111110x + -- then we expect a six-byte character + Result := 6 + end + end + end + +feature {NONE} -- Hexadecimal and strings + + hex_to_integer_32 (s: STRING): INTEGER_32 + -- Hexadecimal string `s' converted to INTEGER_32 value + require + s_not_void: s /= Void + local + i, nb: INTEGER; + char: CHARACTER + do + nb := s.count + + if nb >= 2 and then s.item (2) = 'x' then + i := 3 + else + i := 1 + end + + from + until + i > nb + loop + Result := Result * 16 + char := s.item (i) + if char >= '0' and then char <= '9' then + Result := Result + (char |-| '0') + else + Result := Result + (char.lower |-| 'a' + 10) + end + i := i + 1 + end + end + + hex_to_integer_64 (s: STRING): INTEGER_64 + -- Hexadecimal string `s' converted to INTEGER_64 value + require + s_not_void: s /= Void + local + i, nb: INTEGER; + char: CHARACTER + do + nb := s.count + + if nb >= 2 and then s.item (2) = 'x' then + i := 3 + else + i := 1 + end + + from + until + i > nb + loop + Result := Result * 16 + char := s.item (i) + if char >= '0' and then char <= '9' then + Result := Result + (char |-| '0') + else + Result := Result + (char.lower |-| 'a' + 10) + end + i := i + 1 + end + end + + hex_to_pointer (s: STRING): POINTER + -- Hexadecimal string `s' converted to POINTER value + require + s_not_void: s /= Void + local + val_32: INTEGER_32 + val_64: INTEGER_64 + do + if Pointer_bytes = Integer_64_bytes then + val_64 := hex_to_integer_64 (s) + ($Result).memory_copy ($val_64, Pointer_bytes) + else + val_32 := hex_to_integer_32 (s) + ($Result).memory_copy ($val_32, Pointer_bytes) + end + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/src/xml_encoder.e b/library/text/encoder/src/xml_encoder.e new file mode 100644 index 00000000..23273037 --- /dev/null +++ b/library/text/encoder/src/xml_encoder.e @@ -0,0 +1,267 @@ +note + description: "[ + Summary description for {XML_ENCODER}. + + see: http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references + ]" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date$" + revision: "$Revision$" + +class + XML_ENCODER + +inherit + ENCODER [STRING_32, STRING_8] + + PLATFORM + export + {NONE} all + end + +feature -- Access + + name: STRING = "XML-encoded" + +feature -- Status report + + has_error: BOOLEAN + +feature -- Encoder + + encoded_string (s: STRING_32): STRING_8 + -- XML-encoded value of `s'. + local + i, n: INTEGER + uc: CHARACTER_32 + c: CHARACTER_8 + do + has_error := False + create Result.make (s.count + s.count // 10) + n := s.count + from i := 1 until i > n loop + uc := s.item (i) + if uc.is_character_8 then + c := uc.to_character_8 + inspect c + when '%"' then Result.append_string (""") + when '&' then Result.append_string ("&") + when '%'' then Result.append_string ("'") + when '<' then Result.append_string ("<") + when '>' then Result.append_string (">") + else + Result.extend (c) + end + else + Result.append ("&#") + Result.append (uc.code.out) + Result.extend (';') + end + i := i + 1 + end + end + +feature -- Decoder + + decoded_string (v: STRING_8): STRING_32 + -- The XML-encoded equivalent of the given string + local + i, n: INTEGER + c: CHARACTER + cl_i: CELL [INTEGER] + do + n := v.count + create Result.make (n) + create cl_i.put (0) + from i := 1 until i > n loop + c := v.item (i) + if c = '&' then + cl_i.replace (i) + Result.append_string (next_entity (v, cl_i)) + i := cl_i.item + else + Result.append_character (c.to_character_32) + i := i + 1 + end + end + end + +feature {NONE} -- Implementation: decoder + + next_entity (v: STRING_8; cl_i: CELL [INTEGER]): STRING_32 + -- Return next entity value + -- move index + local + i: INTEGER + c: CHARACTER + is_char: BOOLEAN + is_hexa: BOOLEAN + s: STRING_32 + do + i := cl_i.item + create s.make_empty + i := i + 1 + c := v[i] + if c = '#' then + is_char := True + i := i + 1 + c := v[i] + if c = 'x' then + is_hexa := True + i := i + 1 + c := v[i] + end + end + if is_char then + if is_hexa then + from + until + not c.is_hexa_digit or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + else + from + until + not c.is_digit or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + end + else + from + until + not valid_entity_character (c) or c = ';' + loop + s.append_character (c) + i := i + 1 + c := v[i] + end + end + if c = ';' then + if is_char then + if is_hexa then + -- not yet implemented + s.prepend_character ('x') + s.prepend_character ('#') + s.prepend_character ('&') + s.append_character (';') + Result := s + elseif s.is_integer then + create Result.make (1) + Result.append_code (s.to_natural_32) + else + s.prepend_character ('&') + s.append_character (';') + Result := s + end + else + resolve_entity (s) + Result := s + end + cl_i.replace (i + 1) + else + cl_i.replace (cl_i.item + 1) + s.prepend_character ('&') + has_error := True -- ("Invalid entity syntax " + s) + Result := s + end + end + + resolve_entity (s: STRING_32) + -- Resolve `s' as an entity + --| Hardcoding the xml entities " & ' < and > + require + s_attached: s /= Void + local + l_resolved: BOOLEAN + do + inspect s[1].as_lower + when 'a' then + if + s.count = 3 and then + s[2].as_lower = 'm' and then + s[3].as_lower = 'p' + then -- & + l_resolved := True + s.wipe_out + s.append_character ('&') + elseif -- ' + s.count = 4 and then + s[2].as_lower = 'p' and then + s[3].as_lower = 'o' and then + s[4].as_lower = 's' + then + l_resolved := True + s.wipe_out + s.append_character ('%'') + end + when 'q' then + if + s.count = 4 and then + s[2].as_lower = 'u' and then + s[3].as_lower = 'o' and then + s[4].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('%"') + end + when 'l' then + if + s.count = 2 and then + s[2].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('<') + end + when 'g' then + if + s.count = 2 and then + s[2].as_lower = 't' + then -- " + l_resolved := True + s.wipe_out + s.append_character ('>') + end + else + end + if not l_resolved then + s.prepend_character ('&') + s.append_character (';') + end + end + + valid_entity_character (c: CHARACTER): BOOLEAN + -- Is `c' a valid character in html entity value? + --| such as & + do + inspect + c + when 'a'..'z' then + Result := True + when 'A'..'Z' then + Result := True + when '0'..'9' then + Result := True + else + end + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/tests/test_base64.e b/library/text/encoder/tests/test_base64.e new file mode 100644 index 00000000..e0b0d5ea --- /dev/null +++ b/library/text/encoder/tests/test_base64.e @@ -0,0 +1,49 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_BASE64 + +inherit + EQA_TEST_SET + +feature -- Test routines + + test_base64_encoder + note + testing: "base64" + do + test_base64_encoding ("Il était une fois !") + end + + test_base64_encoding (s: STRING_8) + local + u: STRING_8 + e: STRING_8 + b: BASE64 + do + create b + e := b.encoded_string (s) + u := b.decoded_string (e) + assert ("decoded encoded string is same", u ~ s) + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/tests/test_url_encoder.e b/library/text/encoder/tests/test_url_encoder.e new file mode 100644 index 00000000..40a7e16d --- /dev/null +++ b/library/text/encoder/tests/test_url_encoder.e @@ -0,0 +1,49 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_URL_ENCODER + +inherit + EQA_TEST_SET + +feature -- Test routines + + test_url_encoded_encoder + note + testing: "url-encoded" + do + test_url_encoded_encoding ("http://domain.tld/foo/bar/script.php?test='toto'&foo=bar&title=il était une fois") + end + + test_url_encoded_encoding (s: STRING_32) + local + u: STRING_32 + e: STRING_8 + b: URL_ENCODER + do + create b + e := b.encoded_string (s) + u := b.decoded_string (e) + assert ("decoded encoded string is same", u ~ s) + end + +note + copyright: "Copyright (c) 1984-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/text/encoder/tests/text_xml_encoder.e b/library/text/encoder/tests/text_xml_encoder.e new file mode 100644 index 00000000..824714bd --- /dev/null +++ b/library/text/encoder/tests/text_xml_encoder.e @@ -0,0 +1,47 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_XML_ENCODER + +inherit + EQA_TEST_SET + +feature -- Test routines + + test_xml_encoded_encoder + note + testing: "xml-encoded" + do + test_xml_encoded_encoding ({STRING_32}"il était une fois Ni & Hao (你好)") + end + + test_xml_encoded_encoding (s: STRING_32) + local + u: STRING_32 + e: STRING_8 + b: XML_ENCODER + do + create b + e := b.encoded_string (s) + u := b.decoded_string (e) + assert ("decoded encoded string is same", u ~ s) + end + +note + copyright: "Copyright (c) 1984-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