Eiffel Web Framework


WARNING THIS PAGE IS IN PROGRESS, AS IT IS NOW, IT NEEDS UPDATE SINCE IT DOES NOT REFLECT THE FUTURE INTERFACE

The Eiffel Web Server Gateway Interface

Preface

This specification is a proposition based on recent discussion on the mailing list. This is work in progress, so far nothing had been decided. You can find another proposal at http://eiffel.seibostudios.se/wiki/EWSGI , it has common background and goal, however still differ on specific parts. The main goal for now is to unified those 2 specifications.


Note the following is work in progress, and reflect a specification proposal, rather than the final specification.

2011-08-01

For now, the specification from EWF is done in Eiffel interface please see: https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification

WGI_APPLICATION

deferred class 
    WGI_APPLICATION

feature {NONE} -- Execution

    execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
            -- Execute the request
            -- See `req.input' for input stream
            --     `req.meta_variables' for the CGI meta variable
            -- and `res' for the output buffer
        require
            res_status_unset: not res.status_is_set
        deferred
        ensure
            res_status_set: res.status_is_set
    end

end

WGI_REQUEST

deferred class 
    WGI_REQUEST

feature -- Access: Input

    input: WGI_INPUT_STREAM
            -- Server input channel
        deferred
        end

feature -- Access: extra values

    request_time: detachable DATE_TIME
            -- Request time (UTC)
        deferred
        end

feature -- Access: CGI meta variables       

    meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
            -- Environment variable related to `a_name'
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        deferred
        end

    meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
            -- Environment variable related to `a_name'
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        do
            if attached meta_variable (a_name) as val then
                Result := val.as_string
            end
        end

    meta_variables: ITERABLE [WGI_VALUE]
            -- These variables are specific to requests made with HTTP.
            -- Interpretation of these variables may depend on the value of
            -- SERVER_PROTOCOL.
            --
            -- Environment variables with names beginning with "HTTP_" contain
            -- header data read from the client, if the protocol used was HTTP.
            -- The HTTP header name is converted to upper case, has all
            -- occurrences of "-" replaced with "_" and has "HTTP_" prepended to
            -- give the environment variable name. The header data may be
            -- presented as sent by the client, or may be rewritten in ways which
            -- do not change its semantics. If multiple headers with the same
            -- field-name are received then they must be rewritten as a single
            -- header having the same semantics. Similarly, a header that is
            -- received on more than one line must be merged onto a single line.
            -- The server must, if necessary, change the representation of the
            -- data (for example, the character set) to be appropriate for a CGI
            -- environment variable.
            --
            -- The server is not required to create environment variables for all
            -- the headers that it receives. In particular, it may remove any
            -- headers carrying authentication information, such as
            -- "Authorization"; it may remove headers whose value is available to
            -- the script via other variables, such as "Content-Length" and
            -- "Content-Type".
            --
            -- For convenience it might also include the following CGI entries
        deferred
        end

feature -- Common Gateway Interface - 1.1       8 January 1996

    auth_type: detachable READABLE_STRING_32
            -- 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.
        deferred
        end

    content_length: detachable READABLE_STRING_32
            -- This metavariable is set to the size of the message-body
            -- entity attached to the request, if any, in decimal number of
            -- octets. If no data are attached, then this metavariable is
            -- 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
        end

    content_length_value: NATURAL_64
            -- Integer value related to `content_length"
        deferred
        end

    content_type: detachable READABLE_STRING_32
            -- If the request includes a message-body, CONTENT_TYPE is set to
            -- the Internet Media Type [9] of the attached entity if the type
            -- was provided via a "Content-type" field in the request header,
            -- or if the server can determine it in the absence of a supplied
            -- "Content-type" field. The syntax is the same as for the HTTP
            -- "Content-Type" header field.
            --
            --  CONTENT_TYPE = "" | media-type
            --  media-type   = type "/" subtype *( ";" parameter)
            --  type         = token
            --  subtype      = token
            --  parameter    = attribute "=" value
            --  attribute    = token
            --  value        = token | quoted-string
            --
            -- The type, subtype, and parameter attribute names are not
            -- case-sensitive. Parameter values MAY be case sensitive. Media
            -- types and their use in HTTP are described in section 3.7 of
            -- the HTTP/1.1 specification [8].
            --
            -- Example:
            --
            --  application/x-www-form-urlencoded
            --
            -- There is no default value for this variable. If and only if it
            -- is unset, then the script MAY attempt to determine the media
            -- type from the data received. If the type remains unknown, then
            -- the script MAY choose to either assume a content-type of
            -- application/octet-stream or reject the 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
            -- entity but no "Content-Type" header field, it MAY attempt to
            -- determine the correct datatype, or it MAY omit this
            -- metavariable when communicating the request information to the
            -- script.
        deferred
        end

    gateway_interface: READABLE_STRING_32
            -- This metavariable is set to the dialect of CGI being used by
            -- the server to communicate with the script. Syntax:
            --
            --  GATEWAY_INTERFACE = "CGI" "/" major "." minor
            --  major             = 1*digit
            --  minor             = 1*digit
            --
            -- Note that the major and minor numbers are treated as separate
            -- integers and hence each may be more than a single digit. Thus
            -- CGI/2.4 is a lower version than CGI/2.13 which in turn is
            -- lower than CGI/12.3. Leading zeros in either the major or the
            -- minor number MUST be ignored by scripts and SHOULD NOT be
            -- generated by servers.
            --
            -- This document defines the 1.1 version of the CGI interface
            -- ("CGI/1.1").
            --
            -- Servers MUST provide this metavariable to scripts.
            --
            -- The version of the CGI specification to which this server
            -- complies.  Syntax:
            --
            --  GATEWAY_INTERFACE =  "CGI" "/" 1*digit "." 1*digit
            --
            -- Note that the major and minor numbers are treated as separate
            -- integers and that each may be incremented higher than a single
            -- digit.  Thus CGI/2.4 is a lower version than CGI/2.13 which in
            -- turn is lower than CGI/12.3. Leading zeros must be ignored by
            -- scripts and should never be generated by servers.
        deferred
        end

    path_info: READABLE_STRING_32
            -- The PATH_INFO metavariable specifies a path to be interpreted
            -- by the CGI script. It identifies the resource or sub-resource
            -- to be returned by the CGI script, and it is derived from the
            -- portion of the URI path following the script name but
            -- preceding any query data. The syntax and semantics are similar
            -- to a decoded HTTP URL 'path' token (defined in RFC 2396 [4]),
            -- with the exception that a PATH_INFO of "/" represents a single
            -- void path segment.
            --
            --  PATH_INFO = "" | ( "/" path )
            --  path      = segment *( "/" segment )
            --  segment   = *pchar
            --  pchar     = <any CHAR except "/">
            --
            -- The PATH_INFO string is the trailing part of the <path>
            -- component of the Script-URI (see section 3.2) that follows the
            -- SCRIPT_NAME portion of the path.
            --
            -- Servers MAY impose their own restrictions and limitations on
            -- what values they will accept for PATH_INFO, and MAY reject or
            -- edit any values they consider objectionable before passing
            -- them to the script.
            --
            -- Servers MUST make this URI component available to CGI scripts.
            -- The PATH_INFO value is case-sensitive, and the server MUST
            -- preserve the case of the PATH_INFO element of the URI when
            -- making it available to scripts.
        deferred
        end

    path_translated: detachable READABLE_STRING_32
            -- PATH_TRANSLATED is derived by taking any path-info component
            -- of the request URI (see section 6.1.6), decoding it (see
            -- section 3.1), parsing it as a URI in its own right, and
            -- performing any virtual-to-physical translation appropriate to
            -- 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
            -- supports case-sensitive names. If the repository is only
            -- case-aware, case-preserving, or case-blind with regard to
            -- document names, servers are not required to preserve the case
            -- of the original segment through the translation.
            --
            -- The translation algorithm the server uses to derive
            -- PATH_TRANSLATED is implementation defined; CGI scripts which
            -- use this variable may suffer limited portability.
            --
            -- Servers SHOULD provide this metavariable to scripts if and
            -- only if the request URI includes a path-info component.
        deferred
        end

    query_string: READABLE_STRING_32
            -- A URL-encoded string; the <query> part of the Script-URI. (See
            -- section 3.2.)
            --
            --  QUERY_STRING = query-string
            --  query-string = *uric
            -- The URL syntax for a query string is described in section 3 of
            -- RFC 2396 [4].
            --
            -- Servers MUST supply this value to scripts. The QUERY_STRING
            -- value is case-sensitive. If the Script-URI does not include a
            -- query component, the QUERY_STRING metavariable MUST be defined
            -- as an empty string ("").
        deferred
        end

    remote_addr: READABLE_STRING_32
            -- 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

    remote_host: detachable READABLE_STRING_32
            -- The fully qualified domain name of the client sending the
            -- request to the server, if available, otherwise NULL. (See
            -- section 6.1.9.) Fully qualified domain names take the form as
            -- 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

    remote_ident: detachable READABLE_STRING_32
            -- The identity information reported about the connection by a
            -- RFC 1413 [11] request to the remote agent, if available.
            -- Servers MAY choose not to support this feature, or not to
            -- 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
        end

    remote_user: detachable READABLE_STRING_32
            -- If the request required authentication using the "Basic"
            -- mechanism (i.e., the AUTH_TYPE metavariable is set to
            -- "Basic"), then the value of the REMOTE_USER metavariable is
            -- 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

    request_method: READABLE_STRING_32
            -- The REQUEST_METHOD metavariable is set to the method with
            -- which the request was made, as described in section 5.1.1 of
            -- the HTTP/1.0 specification [3] and section 5.1.1 of the
            -- 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

    script_name: READABLE_STRING_32
            -- The SCRIPT_NAME metavariable is set to a URL path that could
            -- identify the CGI script (rather than the script's output). The
            -- syntax and semantics are identical to a decoded HTTP URL
            -- 'path' token (see RFC 2396 [4]).
            --
            --  SCRIPT_NAME = "" | ( "/" [ path ] )
            --
            -- The SCRIPT_NAME string is some leading part of the <path>
            -- 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

    server_name: READABLE_STRING_32
            -- The SERVER_NAME metavariable is set to the name of the server,
            -- as derived from the <host> part of the Script-URI (see section
            -- 3.2).
            --
            --  SERVER_NAME = hostname | hostnumber
            --
            -- Servers MUST provide this metavariable to scripts.
        deferred
        end

    server_port: INTEGER_32
            -- The SERVER_PORT metavariable is set to the port on which the
            -- request was received, as used in the <port> part of the
            -- Script-URI.
            --
            --  SERVER_PORT = 1*digit
            --
            -- If the <port> 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

    server_protocol: READABLE_STRING_32
            -- The SERVER_PROTOCOL metavariable is set to the name and
            -- revision of the information protocol with which the request
            -- arrived. This is not necessarily the same as the protocol
            -- 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 <scheme> 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

    server_software: READABLE_STRING_32
            -- 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
            -- Servers MUST provide this metavariable to scripts.
        deferred
        end

feature -- HTTP_*

    http_accept: detachable READABLE_STRING_32
            -- Contents of the Accept: header from the current request, if there is one.
            -- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
        deferred
        end

    http_accept_charset: detachable READABLE_STRING_32
            -- Contents of the Accept-Charset: header from the current request, if there is one.
            -- Example: 'iso-8859-1,*,utf-8'.
        deferred
        end

    http_accept_encoding: detachable READABLE_STRING_32
            -- Contents of the Accept-Encoding: header from the current request, if there is one.
            -- Example: 'gzip'.
        deferred
        end

    http_accept_language: detachable READABLE_STRING_32
            -- Contents of the Accept-Language: header from the current request, if there is one.
            -- Example: 'en'.
        deferred
        end

    http_connection: detachable READABLE_STRING_32
            -- Contents of the Connection: header from the current request, if there is one.
            -- Example: 'Keep-Alive'.
        deferred
        end

    http_host: detachable READABLE_STRING_32
            -- Contents of the Host: header from the current request, if there is one.
        deferred
        end

    http_referer: detachable READABLE_STRING_32
            -- 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.
        deferred
        end

    http_user_agent: detachable READABLE_STRING_32
            -- 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.
        deferred
        end

    http_authorization: detachable READABLE_STRING_32
            -- Contents of the Authorization: header from the current request, if there is one.
        deferred
        end

feature -- Extra CGI environment variables

    request_uri: READABLE_STRING_32
            -- The URI which was given in order to access this page; for instance, '/index.html'.
        deferred
        end

    orig_path_info: detachable READABLE_STRING_32
            -- Original version of path_info before processed by Current environment
        deferred
        end

feature -- Query string Parameters

    query_parameters: ITERABLE [WGI_VALUE]
            -- Variables extracted from QUERY_STRING
        deferred
        end

    query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
            -- Parameter for name `n'.
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        deferred
        end

feature -- Form fields and related

    form_data_parameters: ITERABLE [WGI_VALUE]
            -- Variables sent by POST request
        deferred
        end

    form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
            -- Field for name `a_name'.
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        deferred
        end

    uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, READABLE_STRING_GENERAL]
            -- Table of uploaded files information
        deferred
        end

feature -- Cookies  

    cookies: ITERABLE [WGI_VALUE]
            -- Expanded cookies variable
        deferred
        end

    cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
            -- Field for name `a_name'.
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        deferred
        end

feature -- Access: all variables

    items: ITERABLE [WGI_VALUE]
            -- Table containing all the various variables
            -- Warning: this is computed each time, if you change the content of other containers
            -- this won't update this Result's content, unless you query it again
        deferred
        end

    item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
            -- Variable named `a_name' from any of the variables container
            -- and following a specific order
            -- execution, environment, get, post, cookies
        require
            a_name_valid: a_name /= Void and then not a_name.is_empty
        deferred
        end

feature -- Uploaded File Handling

    is_uploaded_file (a_filename: READABLE_STRING_GENERAL): BOOLEAN
            -- Is `a_filename' a file uploaded via HTTP POST
        deferred
        end

feature -- URL Utility

    absolute_script_url (a_path: STRING_8): STRING_8
            -- Absolute Url for the script if any, extended by `a_path'
        deferred
        end

    script_url (a_path: STRING_8): STRING_8
            -- Url relative to script name if any, extended by `a_path'
        require
            a_path_attached: a_path /= Void
        deferred
        end

invariant
    server_name_not_empty: not server_name.is_empty
    server_port_set: server_port /= 0
    request_method_attached: request_method /= Void
    path_info_attached: path_info /= Void
    query_string_attached: query_string /= Void
    remote_addr_attached: remote_addr /= Void
    same_orig_path_info: orig_path_info ~ meta_string_variable ({WGI_META_NAMES}.orig_path_info)
    same_path_info: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
    path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
end

WGI_RESPONSE_BUFFER

deferred class
    WGI_RESPONSE_BUFFER

feature {WGI_APPLICATION} -- Commit

    commit
            -- Commit the current response
        deferred
        ensure
            status_is_set: status_is_set
            header_committed: header_committed
            message_committed: message_committed
        end

feature -- Status report

    header_committed: BOOLEAN
            -- Header committed?
        deferred
        end

    message_committed: BOOLEAN
            -- Message committed?
        deferred
        end

    message_writable: BOOLEAN
            -- Can message be written?
        deferred
        end

feature {WGI_RESPONSE_BUFFER} -- Core output operation

    write (s: READABLE_STRING_8)
            -- Send the string `s'
            -- this can be used for header and body
        deferred
        end

feature -- Status setting

    status_is_set: BOOLEAN
            -- Is status set?
        deferred
        end

    set_status_code (a_code: INTEGER)
            -- Set response status code
            -- Should be done before sending any data back to the client
        require
            status_not_set: not status_is_set
            header_not_committed: not header_committed
        deferred
        ensure
            status_code_set: status_code = a_code
            status_set: status_is_set
        end

    status_code: INTEGER
            -- Response status
        deferred
        end

feature -- Header output operation

    write_headers_string (a_headers: READABLE_STRING_8)
        require
            status_set: status_is_set
            header_not_committed: not header_committed
        deferred
        ensure
            status_set: status_is_set
            header_committed: header_committed
            message_writable: message_writable
        end

    write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
            -- Send headers with status `a_status', and headers from `a_headers'
        require
            status_not_set: not status_is_set
            header_not_committed: not header_committed
        deferred
        ensure
            header_committed: header_committed
            status_set: status_is_set
            message_writable: message_writable
        end

feature -- Output operation

    write_string (s: READABLE_STRING_8)
            -- Send the string `s'
        require
            message_writable: message_writable
        deferred
        end

    write_substring (s: READABLE_STRING_8; a_begin_index, a_end_index: INTEGER)
            -- Send the substring `s[a_begin_index:a_end_index]'
        require
            message_writable: message_writable
        deferred
        end

    write_file_content (fn: READABLE_STRING_8)
            -- Send the content of file `fn'
        require
            message_writable: message_writable
        deferred
        end

    flush
            -- Flush if it makes sense
        deferred
        end
end

Proof-of-concept and reference implementation

Specification overview

The Server/Gateway Side

The Application/Framework Side

Specification Details

Implementation/Application Notes

Questions and Answers

Proposed/Under Discussion

Acknowledgements

References