[ewgi commit] r78 - wiki

1 view
Skip to first unread message

codesite...@google.com

unread,
Oct 21, 2008, 12:25:47 PM10/21/08
to ewgi...@googlegroups.com
Author: huntermorris
Date: Tue Oct 21 09:24:56 2008
New Revision: 78

Modified:
wiki/EWGISpecification.wiki

Log:
Added missing sections marked by TODO

Revised definitions of 'callable' as per mailing list discussion

Revised definition of http header 'other' structure

Revised definition of ewgi_spec dictionary


Modified: wiki/EWGISpecification.wiki
==============================================================================
--- wiki/EWGISpecification.wiki (original)
+++ wiki/EWGISpecification.wiki Tue Oct 21 09:24:56 2008
@@ -19,15 +19,13 @@

== Callables ==

-Throughout this specification, we will use the term "a callable" to
mean "a module (with an ewgi_application behaviour), a function or a fun".
It is up to the server, gateway, or application implementing the callable
to choose the appropriate implementation technique for their needs.
Conversely, a server, gateway, or application that is invoking a callable
must not have any dependency on what kind of callable was provided to it.
Callables are only to be called, not introspected upon.
+Throughout this specification, we will use the term "a callable" to
mean "a first-class function of arity 1." It is up to the server, gateway,
or application implementing the callable to choose the appropriate
implementation technique for their needs. Conversely, a server, gateway,
or application that is invoking a callable MUST NOT have any dependency on
what kind of callable was provided to it. Callables are only to be called,
not introspected upon.

-=== ewgi_application behaviour ===
-
-Callables which are defined as modules may be standard Erlang modules or
parameterised modules, depending on the choice of the application author.
The behaviour is defined as exporting a single method `handle/1` which will
be called in the same manner as an application function would be.
+It is important to note that one of the core features of the Erlang
runtime system, hot code reloading, may be affected by the use of
first-class functions. This specification does not deal directly with the
problems associated with hot code reloading and maintains that it is the
responsibility of the server and application developers to implement the
desired release behaviour.

== The Application/Framework Side ==

-The application is simply a callable that accepts a single 3-tuple
argument. Applications must be able to be invoked more than once, as
virtually all servers/gateways will make such repeated requests. The
callable should return a similarly-structured 3-tuple argument. The
3-tuple may be defined by a record for convenience, but this is not
required. The first element of the context tuple should be the atom
`'ewgi_context'`.
+The application is simply a callable that accepts a single 3-tuple
argument. Applications MUST be able to be invoked more than once, as
virtually all servers/gateways will make such repeated requests. The
callable should return a similarly-structured 3-tuple argument. The
3-tuple may be defined by a record for convenience, but this is not
required. The first element of the context tuple MUST be the atom
`'ewgi_context'`.

(Note: although we refer to it as an "application", this should not be
construed to mean that application developers will use EWGI as a web
programming API! It is assumed that application developers will continue
to use high-level framework services to develop their applications. EWGI
is a tool for framework and server developers, and is not intended to
directly support application developers as "yet another web framework.")

@@ -37,8 +35,10 @@
simple_app({ewgi_context, Request, _Response}) ->
StatusCode = 200,
ReasonPhrase = "OK",
+ Status = {StatusCode, ReasonPhrase},
ResponseHeaders = [{"Content-type", "text/plain"}],
- {ewgi_context, Request, {StatusCode, ReasonPhrase, ResponseHeaders,
[<<"Hello world!">>], undefined}}.
+ Body = [<<"Hello world!">>],
+ {ewgi_context, Request, {Status, ResponseHeaders, Body, undefined}}.
}}}

As stated above, a record may be used for convenience:
@@ -54,9 +54,9 @@

The server or gateway invokes the application callable once for each
request it receives from an HTTP client that is directed at the application.

-TODO: Write example
+An example server using the MochiWeb HTTP toolkit is provided with the
EWGI reference implementation.

-== Middleware: Components that Play Both Sides ==
+== Middleware: Components "that Play Both Sides" ==

Note that a single object may play the role of a server with respect to
some application(s), while also acting as an application with respect to
some server(s). Such "middleware" components can perform such functions as:

@@ -75,24 +75,22 @@
Following is an example which naively converts the output of an
application to uppercase:

{{{
-get_upcase_mw(A) ->
+get_upcase_mw(A) when is_function(A, 1) ->
F = fun(Ctx) ->
- {ewgi_context, Req, Rsp} = case A of
- A when is_function(A, 1) ->
- A(Ctx);
- _ ->
- A:handle(Ctx)
- end,
+ {ewgi_context, Req, Rsp} = A(Ctx),
Body = case element(4, Rsp) of
Body0 when is_function(Body0, 0) ->
upcase_chunks(Body0);
Body0 when is_list(Body0) ->
- upcase_iolist(Body0)
+ upcase_iolist(Body0);
+ Body0 when is_binary(Body0) ->
+ upcase_binary(Body0)
end,
{ewgi_context, Req, setelement(4, Rsp, Body)}
end,
F.

+%% Lazily wrap a stream
upcase_chunks(F0) ->
F = fun() ->
case F0() of
@@ -104,11 +102,14 @@
end,
F.

+upcase_binary(Bin) when is_binary(Bin) ->
+ list_to_binary(string:to_upper(binary_to_list(Bin))).
+
upcase_iolist(L) ->
lists:map(fun(A) when is_integer(A) ->
string:to_upper(A);
(A) when is_binary(A) ->
- list_to_binary(string:to_upper(binary_to_list(A)));
+ upcase_binary(A);
(A) when is_list(A) ->
upcase_iolist(A)
end, L).
@@ -116,11 +117,11 @@

== Specification Details ==

-The application callable must accept one 3-tuple argument. For the sake
of illustration, we have named the second and third elements of this tuple
`request` and `response`, but they obviously are not required to have these
names. A server or gateway must invoke the callable by passing the tuple
argument (e.g. by calling `Result = Application({ewgi_context, Request,
Response})` as shown above). Note that the callable may also be a module
exporting the specified `handle/1` function.
+The application callable must accept one 3-tuple argument. For the sake
of illustration, we have named the second and third elements of this tuple
`request` and `response`, and the specification shall refer to them by
those names. A server or gateway must invoke the callable by passing the
tuple argument (e.g. by calling `Result = Application({ewgi_context,
Request, Response})` as shown above).

=== Request ===

-The `Request` parameter is a tuple containing various CGI-influenced
environment variables. This term must be an 21-tuple, and the application
is allowed to modify the `Request` in any way it desires (except for HTTP
header restrictions outlined later). Element 5 of the tuple must itself be
a 6-tuple including certain EWGI-required terms (described in a later
section), and may also include server-specific extension variables by
making use of the final element (a dictionary). Element 7 of the tuple
must itself be a 8-tuple including certain commonly-encountered HTTP
headers and a dictionary for additional variables. The following records
may be used for convenience.
+The `Request` parameter is a tuple containing various CGI-influenced
environment variables. This term must be an 21-tuple, and the application
is allowed to modify the `Request` in any way it desires (except for HTTP
header restrictions outlined later). Element 5 of the tuple must itself be
a 6-tuple including certain EWGI-required terms (described in a later
section), and may also include server-specific extension variables by
making use of the final element (a bag or multiset). Element 7 of the
tuple must itself be a 8-tuple including certain commonly-encountered HTTP
headers and a dictionary for additional variables. The following records
may be used for convenience.

{{{
-record(ewgi_spec, {
@@ -128,7 +129,7 @@
write_error,
url_scheme,
version,
- data % dict
+ data % set
}).

-record(ewgi_http_headers, {
@@ -138,7 +139,7 @@
http_if_modified_since,
http_user_agent,
http_x_http_method_override,
- other % dict
+ other % multiset
}).

-record(ewgi_request, {
@@ -169,43 +170,43 @@

The `Request` tuple is required to contain these CGI environment
variables, as originally defined by the Common Gateway Interface
specification [2].

-`auth_type`: The type of authentication provided or `'undefined'` if
absent.
+`auth_type`: (Element 2) The type of authentication provided or
`'undefined'` if absent.

-`content_length`: The contents of any `Content-Length` fields in the HTTP
request. May be empty or `'undefined'`.
+`content_length`: (Element 3) The contents of any `Content-Length` fields
in the HTTP request. May be empty or `'undefined'`.

-`content_type`: The contents of any `Content-Type` fields in the HTTP
request. May be empty or `'undefined'`.
+`content_type`: (Element 4) The contents of any `Content-Type` fields in
the HTTP request. May be empty or `'undefined'`.

-`ewgi`: See section below
+`ewgi`: (Element 5) See section below

-`gateway_interface`: TODO
+`gateway_interface`: (Element 6) The gateway interface and revision used.
Should be `EWGI/1.1` for this version of the specification.

-`http_headers`: See section below
+`http_headers`: (Element 7) See section below

-`path_info`: The remainder of the request URL's "path", designating the
virtual "location" of the request's target within the application. This
may be an empty string, if the request URL targets the application root and
does not have a trailing slash.
+`path_info`: (Element 8) The remainder of the request URL's "path",
designating the virtual "location" of the request's target within the
application. This may be an empty string, if the request URL targets the
application root and does not have a trailing slash.

-`path_translated`: TODO
+`path_translated`: (Element 9) The path as may be translated by the server
to a physical location.

-`query_string`: The portion of the request URL that follows the `"?"`, if
any. May be empty or `'undefined'`.
+`query_string`: (Element 10) The portion of the request URL that follows
the `"?"`, if any. May be empty or `'undefined'`.

-`remote_addr`: TODO
+`remote_addr`: (Element 11) The remote IP address of the client issuing
the request

-`remote_host`: TODO
+`remote_host`: (Element 12) The remote hostname of the client issuing the
request. May be empty or `'undefined'`.

-`remote_ident`: TODO
+`remote_ident`: (Element 13) If the server supports RFC 931
identification, this variable may be set to the remote user name. Should
only be used for logging purposes.

-`remote_user`: TODO
+`remote_user`: (Element 14) If authentication is supported by the server
(or middleware), this should be set to the authenticated username.

-`remote_user_data`: TODO
+`remote_user_data`: (Element 15) Any additional data provided by the
authentication mechanism.

-`request_method`: The HTTP request method, such as `"GET"` or `"POST"`.
This cannot ever be an empty string, and so is always required.
+`request_method`: (Element 16) The HTTP request method, such as `"GET"` or
`"POST"`. This cannot ever be an empty string, and so is always required.

-`script_name`: The initial portion of the request URL's "path" that
corresponds to the application object, so that the application knows its
virtual "location". This may be an empty string, if the application
corresponds to the "root" of the server.
+`script_name`: (Element 17) The initial portion of the request
URL's "path" that corresponds to the application object, so that the
application knows its virtual "location". This may be an empty string, if
the application corresponds to the "root" of the server.

-`server_name`, `server_port`: When combined with `script_name` and
`path_info`, these variables can be used to complete the URL. Note,
however, that `http_host`, if present, should be used in preference to
`server_name` for reconstructing the request URL. See the
[#url-reconstruction URL Reconstruction]section below for more detail.
`server_name` and `server_port` can never be empty strings, and so are
always required.
+`server_name`, `server_port`: (Element 18,19) When combined with
`script_name` and `path_info`, these variables can be used to complete the
URL. Note, however, that `http_host`, if present, should be used in
preference to `server_name` for reconstructing the request URL. See the
[#url-reconstruction URL Reconstruction]section below for more detail.
`server_name` and `server_port` can never be empty strings, and so are
always required.

-`server_protocol`: The version of the protocol the client used to send the
request. Typically this will be something like `"HTTP/1.0"` or
`"HTTP/1.1"`and may be used by the application to determine how to treat
any HTTP request headers. (This variable should probably be called
`request_protocol`, since it denotes the protocol used in the request, and
is not necessarily the protocol that will be used in the server's
response. However, for compatibility with CGI we have to keep the existing
name).
+`server_protocol`: (Element 20) The version of the protocol the client
used to send the request. Typically this will be something like
`"HTTP/1.0"` or `"HTTP/1.1"`and may be used by the application to determine
how to treat any HTTP request headers. (This variable should probably be
called `request_protocol`, since it denotes the protocol used in the
request, and is not necessarily the protocol that will be used in the
server's response. However, for compatibility with CGI we have to keep the
existing name).

-`server_software`: TODO
+`server_software`: (Element 21) The name and revision of the server
software answering the request.

==== EWGI-specification parameters ====

@@ -215,9 +216,9 @@

`url_scheme`: (Element 4) A string representing the "scheme" portion of
the URL at which the application is being invoked. Normally, this will have
the value `"http"` or `"https"` where appropriate.

-`version`: (Element 5) The tuple `{1,0}`, representing EWGI major version
1, minor version 0 (1.0).
+`version`: (Element 5) The tuple `{1,1}`, representing EWGI major version
1, minor version 1.

-`data`: (Element 6) A dictionary which can be used for server or
application-specific data to be included with the request. A common use
for this dictionary is in configuring higher-level web frameworks or
providing cached data. Additionally, a server or gateway should attempt to
provide as many other CGI variables as are applicable. In addition, if SSL
is in use, the server or gateway should also provide as many of the Apache
SSL environment variables [5] as are applicable, such as `https` and
`ssl_protocol`. Note, however, that an application that uses any CGI
variables other than the ones listed above are necessarily non-portable to
web servers that do not support the relevant extensions. An EWGI-compliant
server or gateway should document what variables it provides, along with
their definitions as appropriate. Applications should check for the
presence of any variables they require, and have a fallback plan in the
event such a variable is `'undefined'`.
+`data`: (Element 6) A dictionary (implemented by the OTP module
`gb_trees`) which can be used for server or application-specific data to be
included with the request. A common use for this dictionary is in
configuring higher-level web frameworks or providing cached data.
Additionally, a server or gateway should attempt to provide as many other
CGI variables as are applicable. In addition, if SSL is in use, the server
or gateway should also provide as many of the Apache SSL environment
variables [5] as are applicable, such as `https` and `ssl_protocol`. Note,
however, that an application that uses any CGI variables other than the
ones listed above are necessarily non-portable to web servers that do not
support the relevant extensions. An EWGI-compliant server or gateway should
document what variables it provides, along with their definitions as
appropriate. Applications should check for the presence of any variables
they require, and have a fallback plan in the event such a variable is
`'undefined'`.

==== HTTP headers ====

@@ -235,20 +236,19 @@

`http_x_http_method_override`: (Element 7) The `X-Http-Method-Override:`
header. While not part of the HTTP 1.1 specification, this header can be
used to overcome a common browser limitation which prevents browsers from
sending a `PUT` or `DELETE` request to a URI.

-`other`: (Element 8) A dictionary which contains all other HTTP request
headers. The keys of the dictionary should be lower-case representations of
the header names.
+`other`: (Element 8) A multiset (implemented by the OTP module `gb_trees`)
which contains all other HTTP request headers. The keys of the dictionary
should be lower-case representations of the header names and the values
should be a list of tuples of the form {`HeaderName`, `HeaderValue`}.
Servers SHOULD attempt to preserve the original case of header names in the
tuple list.

==== Notes ====

-Missing variables (such as `remote_user` when no authentication has
occurred) should be defined by the atom `'undefined'`. Also note that
CGI-defined variables must be strings if they are defined. It is a
violation of this specification for a CGI variable's value to be of any
type other than `string` (except the atom `'undefined'`).
+Missing variables (where allowed, such as `remote_user` when no
authentication has occurred) should be defined by the atom `'undefined'`.
Also note that CGI-defined variables must be strings if they are defined.
It is a violation of this specification for a CGI variable's value to be of
any type other than `string` or the `'undefined'` atom.

=== Response ===

-The `Response` parameter is a 6-tuple of the form `{ewgi_response,
StatusCode, ReasonPhrase, HeaderList, MessageBody, Error}`. and A
convenient record definition is:
+The `Response` parameter is a 5-tuple of the form `{ewgi_response,
{StatusCode, ReasonPhrase}, HeaderList, MessageBody, Error}`. and A
convenient record definition is:

{{{
-record(ewgi_response, {
- status_code,
- reason_phrase,
+ status={200, "OK"},
headers=[],
message_body,
err
@@ -265,7 +265,7 @@

==== Headers ====

-`Headers` is a list of `{HeaderName, HeaderValue}` tuples describing the
HTTP response header.
+`Headers` is a list of `{HeaderName, HeaderValue}` tuples describing the
HTTP response headers.

Each `HeaderName` must be a valid HTTP header field-name (as defined by
RFC 2616, Section 4.2), without a trailing colon or bother punctuation.
Note: `HeaderName` is case insensitive, but should be lower-case for
optimising comparisons. (A reminder for server/gateway authors: be sure to
take that into consideration when examining application-supplied headers).

@@ -283,13 +283,13 @@

==== Message Body ====

-The `MessageBody` parameter is either an `iolist` or a "stream," which is
a lazy list-like structure. A stream is a zero-arity function which
returns either the empty tuple `{}` or a 2-tuple of the form `{Head, Tail}`
where `Head` is an `iolist` and `Tail` is another stream. Servers may
choose to transmit message bodies represented by a stream using the chunked
transfer encoding. However, the server or gateway must transmit `iolist`s
to the client in an unbuffered fashion, completing the transmission of each
`iolist` before requesting another one. (In other words, applications
should perform their own buffering. See the [#buffering-and-streaming
Buffering and Streaming] section below for more on how application output
must be handled).
+The `MessageBody` parameter is either an `iolist` or a "stream," which is
a lazy, recursive list-like structure. A stream is a zero-arity function
which returns either the empty tuple `{}` or a 2-tuple of the form `{Head,
Tail}` where `Head` is an `iolist` and `Tail` is another stream. Servers
may choose to transmit message bodies represented by a stream using the
chunked transfer encoding. However, the server or gateway must transmit
`iolist`s to the client in an unbuffered fashion, completing the
transmission of each `iolist` before requesting another one. (In other
words, applications should perform their own buffering. See the
[#buffering-and-streaming Buffering and Streaming] section below for more
on how application output must be handled).

The server or gateway should not alter the `iolist` returned by the
application in any way. The application is responsible for ensuring that
the `iolist`(s) to be written are in a format suitable for the client.
However, the server or gateway may apply HTTP transfer encodings or perform
other transformations for the purpose of implementing HTTP features such as
byte-range transmission. (See [#other-http-features Other HTTP Features],
below, for more details).

== EWGI Reference Implementation ==

-The EWGI reference implementation includes an API module `ewgi_api` which
defines helper functions to access and modify the EWGI context, parse query
strings, etc. It also includes a behaviour module `ewgi_application` which
contains convenience functions for dealing with application functions and
modules, including the `behaviour_info/1` function. An include file
(`include/ewgi.hrl`) is also provided, which contains macros for standard
HTTP status values and the convenience record definitions. These may be
used to help development of servers and applications, but should not be
required.
+The EWGI reference implementation includes an API module `ewgi_api` which
defines helper functions to access and modify the EWGI context, parse query
strings, etc. It also includes a module `ewgi_application` which contains
convenience functions for dealing with application functions as well as
sample middleware components. An include file (`include/ewgi.hrl`) is also
provided, which contains macros for standard HTTP status values and the
convenience record definitions. These may be used to help development of
servers and applications, but should not be required.

== Buffering and Streaming ==

Reply all
Reply to author
Forward
0 new messages