# mod_esi

### MODULE

mod_esi

### MODULE SUMMARY

Efficient Erlang Scripting

### DESCRIPTION

The Erlang Scripting Interface (ESI) provides a tight and efficient interface to the execution of Erlang functions. Erlang functions can be executed with two alternative schemes, `eval` and `erl`. Both of these schemes can utilize the functionality in an Erlang node efficiently.

Even though the server supports CGI-1.1 the use of the Erlang Scripting Interface (ESI) is encouraged for reasons of efficiency. CGI is resource intensive because of it's design. CGI requires the server to fork a new OS process for each executable it needs to start.

An Erlang function can be written and executed as a CGI script by using `erl_call(3)` in the erl_interface library, for example. The cost is a forked OS process, as described above. This is a waste of resources, at least when the Web server itself is written in Erlang (as in this case).

The following config directives are described:

- ErlScripAlias
- EvalScriptAlias
- ErlScriptNoCache
- ErlScriptTimeout

### ERL SCHEME

The `erl` scheme is designed to mimic plain CGI, but without the extra overhead. An URL which calls an Erlang `erl` function has the following syntax (regular expression):

    http://your.server.org/***/Mod[:/]Func(?QueryString|/PathInfo)

The module (`Mod`) referred to must be found in the code path, and it must define a function (`Func`) with an arity of two or three i.e. `Func(Env,Input)` or Func(SessionID,Env,Input). `Env` contains information about the connecting client (see below), and `Input` the `QueryString` or `PathInfo` as defined in the CGI specification. SessionID is a identifier that is used to send parts of the web page back to the user through the function mod_esi:deliver/2

`***` above depends on how the ErlScriptAlias config directive has been used. Data returned from the function with arity of two must furthermore take the form as specified in the CGI specification.

It is preferable to use the callback function with an arity of three, since the function can send the data back to the clients in parts instead of generating the whole page before it is sent. The Web server sends the data back to HTTP/1.1 compliant clients with chunked encoding this means that the Content-Length header field is not necessary, and should indeed be avoided.

mod_esi assumes that if the first chunk of data delivered to the client through the function `mod_esi:deliver/2` contains all HTTP-header fields the script will generate. I the first chunk does not contain the string `"\r\n\r\n"c` mod_esi assumes that the script not will generate any header data.

Take a look at `httpd_example.erl` in the code release (`UNIX: $INETS/src, Windows: %INETS\src`) for a clarifying example. Start an example server as described in httpd:start/0 and test the following from a browser (The server name for your example server will differ!):

`http://your.server.org:8888/cgi-bin/erl/httpd_example/newformat`
  and a call will be made to `httpd_example:newformat/3` Something like this will promptly be shown in the browser:

           This new format is nice.
                This new format is nice.
                This new format is nice.

`http://your.server.org:8888/cgi-bin/erl/httpd_example/get`
  and a call will be made to `httpd_example:get/2` and two input fields and a Submit button will promptly be shown in the browser. Enter text into the input fields and click on the Submit button. Something like this will promptly be shown in the browser:

      Environment:
      [{query_string,"input1=blaha&input2=blaha"},
       {server_software,"eddie/2.2"},
       {server_name,"localhost"},
       {gateway_interface,"CGI/1.1"},
       {server_protocol,"HTTP/1.0"},
       {server_port,8080},
       {request_method,"GET"},
       {remote_addr,"127.0.0.1"},
       {script_name,"/cgi-bin/erl/httpd_example:get?input1=blaha&
                                                    input2=blaha"},
       {http_accept_charset,"iso-8859-1,*,utf-8"},
       {http_accept_language,"en"},
       {http_accept,"image/gif, image/x-xbitmap, image/jpeg,
                                                 image/pjpeg, */*"},
       {http_host,"localhost:8080"},
       {http_user_agent, "Mozilla/4.03 [en] (X11;
                                             I; Linux 2.0.30 i586)"},
       {http_connection,"Keep-Alive"},
       {http_referer,
        "http://localhost:8080/cgi-bin/erl/
               httpd_example/get"}]
      Input:
       input1=blaha&input2=blaha
      Parsed Input:
       [{"input1","blaha"},{"input2","blaha"}]

`http://your.server.org:8888/cgi-bin/erl/httpd_example:post`
  A call will be made to `httpd_example:post/2`. The same thing will happen as in the example above but the HTTP POST method will be used instead of the HTTP GET method.
`http://your.server.org:8888/cgi-bin/erl/httpd_example:yahoo`
  A call will be made to to `httpd_example:yahoo/2` and the Yahoo! site will promptly be shown in your browser.

| httpd:parse_query/1 is used to generate the `Parsed Input: ...` data in the example above. If a client closes the connection prematurely a message will be sent to the function, that is either `{tcp_closed,_}` or `{_,{socket_closed,_}}`.

### EVAL SCHEME

| The `eval` scheme can seriously threaten the integrity of the Erlang node housing a Web server, for example:
    http://your.server.org/eval?httpd_example:
           print(atom_to_list(apply(erlang,halt,[])))
which effectively will close down the Erlang node, that is use the `erl` scheme instead until this security breach has been fixed. Today there are no good way of solving this problem and therefore Eval Scheme may be removed in future release-s of Inets.

The `eval` scheme is straight-forward and does not mimic the behavior of plain CGI. An URL which calls an Erlang `eval` function has the following syntax:

    http://your.server.org/***/Mod:Func(Arg1,...,ArgN)

The module (`Mod`) referred to must be found in the code path, and data returned by the function (`Func`) is passed back to the client. `***` depends on how the EvalScriptAlias config directive has been used. Data returned from the function must furthermore take the form as specified in the CGI specification.

Take a look at `httpd_example.erl` in the code release (`UNIX: $INETS/src, Windows: %INETS\src`) for an example. Start an example server as described in httpd:start/0 and test the following from a browser (The server name for your example server will differ!):

`http://your.server.org:8888/eval?httpd_example:print("Hi!")`
  and a call will be made to `httpd_example:print/1` and "Hi!" will promptly be shown in your browser.

### DIRECTIVE: "ErlScriptAlias"

Syntax: `ErlScriptAlias` url-path allowed-module allowed-module ...
Default: - None -
Module: mod_esi(3)

`ErlScriptAlias` marks all URLs matching `url-path` as erl scheme scripts. A matching URL is mapped into a specific module and function. The module must be one of the `allowed-module`:s. For example:

    ErlScriptAlias /cgi-bin/hit_me httpd_example md4

and a request to `http://your.server.org/cgi-bin/hit_me/httpd_example:yahoo` would refer to `httpd_example:yahoo/2`. Refer to the Erl Scheme description above.

### DIRECTIVE: "ErlScriptNoCache"

Syntax: `ErlScriptNoCache` true | false
Default: false
Module: mod_esi(3)

If `ErlScriptNoCache` is set to true the server will add http header fields that prevents proxies from caching the page. This is generally a good idea for dynamic content, since the content often vary between each request.

          ErlScriptNoCache true

### DIRECTIVE: "ErlScriptTimeout"

Syntax: `ErlScriptTimeout` seconds
Default: 15
Module: mod_esi(3)

If `ErlScriptTimeout` sets the time in seconds the server will wait between each chunk of data is delivered through mod_esi:deliver/2 when the new Erl Scheme format, that takes three argument is used.

          ErlScriptTimeout 15

### DIRECTIVE: "EvalScriptAlias"

Syntax: `EvalScriptAlias` url-path allowed-module allowed-module ...
Default: - None -
Module: mod_esi(3)

`EvalScriptAlias` marks all URLs matching `url-path` as eval scheme scripts. A matching URL is mapped into a specific module and function. The module must be one of the `allowed-module`:s. For example:

    EvalScriptAlias /cgi-bin/hit_me_to httpd_example md5

and a request to `http://your.server.org/cgi-bin/hit_me_to/httpd_example:print("Hi!")` would refer to `httpd_example:print/1`. Refer to the Eval Scheme description above.

### EWSAPI MODULE INTERACTION

Uses the following EWSAPI interaction data, if available:

`{remote_user,RemoteUser}`
  as defined in mod_auth(3).

Exports the following EWSAPI interaction data, if possible:

`{mime_type,MimeType}`
  The file suffix of the incoming URL mapped into a `MimeType` as defined in the Mime Type Settings section of `httpd_core(3)`.

Uses the following EWSAPI functions:

- mod_alias:real_name/3
- mod_cgi:status_code/1

### EXPORTS

`deliver(SessionID, Data) -> ok | {error,Reason}`

Types:

`SessionID = term()`
`Data = string()`
`Reason = term()`

This function is only intended to be used from functions called by the Erl Scheme interface to deliver parts of the content to the user.

Sends data from a Erl Scheme script back to the client. Note that if any HTTP-header fields will be sent back to the client they must be in the first call to deliver/2. Do not assume anything about the data type of SessionID, the SessionID must be the SessionID from the Erl Scheme call.

### ESWAPI CALLBACK FUNCTIONS

### EXPORTS

`Module:Function(Env, Input)-> Response`

Types:

``
`Env = [EnvironmentDirectives] ++ ParsedHeader`
`EnvironmentDirectives = {Key,Value}`
`Key = query_string | content_length, server_software, gateway_interface, server_protocol, server_port, request_method, remote_addr, script_name. <v>Input = Response = string()`

The `Module` must be found in the code path and export `Function` with an arity of two. An erlScriptAlias must also be set up in the configuration file for the Web server.

If the HTTP request is a post request and a body is sended then content_length will be the length of the posted data. If get is used query string will be the data after ? in the url.

ParsedHeader is the HTTP request as a key value tuple list. The keys in parsed header will be the in lower case.

This callback format consumes quite much memory since the whole response must be generated before it is sent to the user. Therefore it is better to use the callback function with an arity of three.

`Module:Function(SessionID, Env, Input)-> void`

Types:

`SessionID = term()`
`Env = [EnvironmentDirectives] ++ ParsedHeader`
`EnvironmentDirectives = {Key,Value}`
`Key = query_string | content_length, server_software, gateway_interface, server_protocol, server_port, request_method, remote_addr, script_name. <v>Input = Response = string()`

For information about Environment and Input see `Module:Function/2` above. SessionID is a identifier the server use when `deliver/2` is called, do not assume any-thing about the datatype.

Use this callback function to dynamicly generate dynamic web content. when a part of the page is generated send the data back to the client through `deliver/2`. Note that the first chunk of data sent to the client must at least contain all HTTP header fields that the response will generate. If the first chunk not contains End of HTTP header that is `"\r\n\r\n"` the server will assume that no HTTP header fields will be generated.

### SEE ALSO

httpd(3), mod_alias(3), mod_auth(3), mod_security(3), mod_cgi(3)

### AUTHORS

Joakim Grebenö - support@erlang.ericsson.se

inets 3.0.6
Copyright © 1991-2003 Ericsson Utvecklings AB