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 00000000..6b18c88f
Binary files /dev/null and b/library/server/libfcgi/spec/lib/win64/msc/libfcgi.dll differ
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 00000000..839cda3f
Binary files /dev/null and b/library/server/libfcgi/spec/lib/win64/msc/libfcgi.lib differ
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 00000000..83d69a06
Binary files /dev/null and b/library/server/libfcgi/spec/lib/windows/msc/libfcgi.dll differ
diff --git a/library/server/libfcgi/spec/lib/windows/msc/libfcgi.lib b/library/server/libfcgi/spec/lib/windows/msc/libfcgi.lib
new file mode 100644
index 00000000..01af4f19
Binary files /dev/null and b/library/server/libfcgi/spec/lib/windows/msc/libfcgi.lib differ
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 ("