embOS/IP web server

The embOS/IP web server is an optional extension which adds the HTTP protocol to the stack. It combines a maximum of performance with a small memory footprint. The web server allows an embedded system to present web pages with dynamically generated content. It comes with all features typically required by embedded systems: multiple connections, authentication, forms and low RAM usage. RAM usage has been kept to a minimum by smart buffer handling.

The web server implements the relevant parts of the following Request For Comments (RFC):

RFC Description
[RFC 1945] HTTP - Hypertext Transfer Protocol -- HTTP/1.0
Direct link: http://tools.ietf.org/html/rfc1945
[RFC 2616] HTTP - Hypertext Transfer Protocol -- HTTP/1.1
Direct link: http://tools.ietf.org/html/rfc2616

 

Feature list

  • Low memory footprint.
  • Dynamic web pages (Server Side Includes).
  • Authentication supported.
  • Forms: POST and GET support.
  • Multiple connections supported.
  • HTML to C converter included.
  • r/o file system included.
  • Independent of the file system: any file system can be used.
  • Independent of the TCP/IP stack: any stack with sockets can be used.
  • Demo with authentication, various forms, dynamic pages included.
  • Project for executable on PC for Microsoft Visual Studio included.

Requirements

TCP/IP stack

The embOS/IP web server requires a TCP/IP stack. It is optimized for embOS/IP, but any RFC-compliant TCP/IP stack can be used. The shipment includes a Win32 simulation, which uses the standard Winsock API and an implementation which uses the socket API of embOS/IP.

Multi tasking

The web server needs to run as a separate thread. Therefore, a multi tasking system is required to use the embOS/IP web server.

HTTP backgrounds

HTTP is a communication protocol originally designed to transfer information via hypertext pages. The development of HTTP is coordinated by the IETF (Internet Engineering Task Force) and the W3C (World Wide Web Consortium). The current protocol version is 1.1.

HTTP communication basics

HTTP is a challenge and response protocol. A client initiates a TCP connection to the web server and sends a HTTP request. A HTTP request starts with a method token. [RFC 2616] defines 8 method tokens. The method token indicates the method to be performed on the requested resource. embOS/IP web server supports all methods which are typically required by an embedded web server.

HTTP method Description
GET The GET method means that it retrieves whatever information is identified by the Request-URI.
HEAD The HEAD method means that it retrieves the header of the content which is identified by the Request-URI.
POST The POST method submits data to be processed to the identified resource. The data is included in the body of the request.

The following example shows parts of a HTTP session, where a client (for example, 192.168.1.75) asks the embOS/IP web server for the hypertext page example.html.
The request is followed by a blank line, so that the request ends with a double new line, each in the form of a carriage return followed by a line feed.

GET /example.html HTTP/1.1
Host: 192.168.1.75

The first line of every response message is the Status-Line, consisting of the protocol version followed by a numeric status code. The Status-Line is followed by the content-type, the server, expiration and the transfer-encoding. The server response ends with an empty line, followed by length of content that should be transfered. The length indicates the length of the web page in bytes.

HTTP/1.1 200 OK
Content-Type: text/html
Server: embOS/IP
Expires: THU, 26 OCT 1995 00:00:00 GMT
Transfer-Encoding: chunked

A3

Thereafter, the web server sends the requested hypertext page to the client. The zero at the end of the web page followed by an empty line signalizes that the transmission of the requested web page is complete.

<HTML>
  <HEAD>
    <TITLE>embOS/IP examples</TITLE>
  </HEAD>
  <BODY>
    <CENTER>
      <H1>Website: example.htm</H1>
    </CENTER>
  </BODY>
</HTML>

0

HTTP communication basics

The first line of a HTTP response is the Status-Line. It consists of the used protocol version, a status code and a short textual description of the Status-Code. The Status-Code element is a 3-digit integer result code of the attempt to understand and satisfy the request.

The first digit of the Status-Code defines the class of response. The last two digits do not have any categorization role. There are 5 values for the first digit:

  • 1xx: Informational - Request received, continuing process.
  • 2xx: Success - The action was successfully received, understood, and accepted.
  • 3xx: Redirection - Further action must be taken in order to complete the request.
  • 4xx: Client Error - The request contains bad syntax or cannot be fulfilled.
  • 5xx: Server Error - The server failed to fulfill an apparently valid request.

embOS/IP web server supports a subset of the defined HTTP status codes. Refer to [RFC 2616] for a complete list of defined status-codes.

Common Gateway Interface (CGI)

A Common Gateway Interface (CGI) like interface is used to implement dynamic content in web pages. Every web page will be parsed by the server each time a request is received. The server searches the web page for a special tag. In the default configuration, the searched tag starts <!--#exec cgi=" and ends with "-->. The tag will be analyzed and the parameter will be extracted. This parameter specifies a server-side command and will be given to the user application, which can handle the command. The following screenshot shows the example page index.htm.

The HTML source for the page includes the following line:

<!--#exec cgi="Counter"-->


When the web page is requested, the server parses the tag and the parameter Counter is searched for in an array of structures of type WEBS_CGI. The structure includes a string to identify the command and a pointer to the function which should be called if the parameter is found.

typedef struct {
  const char * sName; // e.g. "Counter"
  void (*pf)(WEBS_OUTPUT * pOutput, const char * sParameters,   const char * sValue);
} WEBS_CGI;

In the example, Counter is a valid parameter and the function _callback_ExecCounter will be called. You need to implement the WEBS_CGI array and the callback functions in your application.

static const WEBS_CGI _aCGI[] = {
  {"Counter" , _callback_ExecCounter },
  {"GetOSInfo" , _callback_ExecGetOSInfo},
  {"GetIPAddr" , _callback_ExecGetIPAddr},
  {NULL}
};

ExecCounter() is a simple example of how to use the CGI feature. It returns a string that includes the value of a variable which is incremented with every call to ExecCounter().

void ExecCounter( WEBS_OUTPUT * pOutput, const char * sParameters, const char * sValue ) {
  char ac[40];
  static char Cnt = 1;
  sprintf(ac, "You are visitor no.: %d", Cnt);
  IP_WEBS_SendString(pOutput, ac);
  Cnt++;
}

Add new CGI functions to your web server application

To define new CGI functions, three things have to be done.
1. Add a new command name which should be used as tag to the WEBS_CGI structure.
For example: UserCGI

static const WEBS_CGI _aCGI[] = {
  {"Counter" , _callback_ExecCounter },
  {"GetOSInfo" , _callback_ExecGetOSInfo},
  {"GetIPAddr" , _callback_ExecGetIPAddr},
  {"UserCGI" , _callback_ExecUserCGI },
  {NULL}
};

2. Implement the new function in your application source code.

void _callback_ExecUserCGI( WEBS_OUTPUT * pOutput, const char * sParameters const char * sValue ) {
/* Add application code here */
}

3. Add the new tag to the source code of your web page:

<!--#exec cgi="UserCGI"-->

Authentication

"HTTP/1.0", includes the specification for a Basic Access Authentication scheme. The basic authentication scheme is a non-secure method of filtering unauthorized access to resources on an HTTP server, because the user name and password are passed over the network as clear text. It is based on the assumption that the connection between the client and the server can be regarded as a trusted carrier. As this is not generally true on an open network, the basic authentication scheme should be used accordingly.

The basic access authentication scheme is described in:

RFC Description
[RFC 2617] HTTP Authentication: Basic and Digest Access Authentication
Direct link: http://tools.ietf.org/html/rfc2617

The "basic" authentication scheme is based on the model that the client must authenticate itself with a user-ID and a password for each realm. The realm value should be considered an opaque string which can only be compared for equality with other realms on that server. The server will service the request only if it can validate the user-ID and password for the protection space of the Request-URI. There are no optional authentication parameters. Upon receipt of an unauthorized request for a URI within the protection space, the server should respond with a challenge like the following:

WWW-Authenticate: Basic realm="embOS/IP embedded web server"

where "embOS/IP embedded web server" is the string assigned by the server to identify the protection space of the Request-URI. To receive authorization, the client sends the user-ID and password, separated by a single colon (":") character, within a base64 encoded string in the credentials. If the user agent wishes to send the user-ID "user" and password "pass", it would use the following header field:

Authorization: Basic dXNlcjpwYXNz

Authentication example

The client requests a resource for which authentication is required:

GET /conf/Authen.htm HTTP/1.1
Host: 192.168.1.75

The server answers the request with a "401 Unauthorized" status page. The header of the 401 error page includes an addional line WWW-Authenticate. It includes the realm for which the proper username and password should be transmitted from the client (for example, a web browser).

HTTP/1.1 401 Unauthorized
Date: Mon, 04 Feb 2008 17:00:44 GMT
Server: embOS/IP
Accept-Ranges: bytes
Content-Length: 695
Connection: close
Content-Type: text/html
X-Pad: avoid browser bug
WWW-Authenticate: Basic realm="embOS/IP embedded web server"

<HTML>
  <HEAD><TITLE>401 Unauthorized</TITLE></HEAD>
  <BODY>
    <H1>401 Unauthorized</H1>
    Browser not authentication-capable or authentication failed.<P>
  </BODY>
</HTML>

The client interprets the header and opens a dialog box to enter the username and password combination for the realm of the resource.

Enter the proper user name/password combination for the requested realm and confirm with the OK button. The client encodes the user name/password combination to a base64 encoded string and requests the resource again. The request header is enhanced by the following line: Authorization: Basic dXNlcjpwYXNz

GET /conf/Authen.htm HTTP/1.1
Host: 192.168.1.75
Authorization: Basic dXNlcjpwYXNz

The server decodes the user name/password combination and checks if the decoded string matches to the defined user name/password combination of the realm. If the strings are identical, the server delivers the page. If the strings are not identical, the server answers again with a "401 Unauthorized" status page.

HTTP/1.1 200 OK
Content-Type: text/html
Server: embOS/IP
Expires: THU, 26 OCT 1995 00:00:00 GMT
Transfer-Encoding: chunked

200
<HTML>
  <HEAD>
    <TITLE>web server configuration</TITLE>
  </HEAD>
  <BODY>
    <!-- Content of the page -->
  </BODY>
</HTML>

0

Configuration of the authentication

The embOS/IP web server checks the access rights of every resource before returning it. The user can define different realms to separate different parts of the web server resources. An array of WEBS_ACCESS_CONTROL structures has to be implemented in the user application. Refer to Structure WEBS_ACCESS_CONTROL on page 164 for detailed information about the elements of the WEBS_ACCESS_CONTROL structure. If no authentication should be used, the array includes only one entry for the root path.

WEBS_ACCESS_CONTROL _aAccessControl[] = {
  { "/", NULL, NULL },
  0
};

To define a realm "conf", an additional WEBS_ACCESS CONTROL entry has to be implemented.

WEBS_ACCESS_CONTROL _aAccessControl[] = {
  { "/conf/", "Login for configuration", "user:pass" },
  { "/", NULL, NULL },
  0
};

The string "Login for configuration" defines the realm. "user:pass" is the user name/password combination stored in one string.

Form handling

The embOS/IP web server supports both POST and GET actions to receive form data from a client. POST submits data to be processed to the identified resource. The data is included in the body of the request. GET is normally only used to requests a resource, but it is also possible to use GET for actions in web applications. Data processing on server side might create a new resource or update existing resources or both.

Every HTML form consists of input items like textfields, buttons, checkboxes, etc. Each of these input items has a name tag. When the user places data in these items in the form, that information is encoded into the form data. Form data is a stream of <name>=<value> pairs separated by the "&" character. The value each of the input item is given by the user is called the value. The <name>=<value> pairs are URL encoded, which means that spaces are changed into "+" and special characters are encoded into hexadecimal values. Refer to [RFC 1738] for detailed information about URL encoding. The parsing and decoding of form data is handled by the embOS/IP web server. Thereafter, the server calls a callback function with the decoded and parsed strings as parameters. The responsibility to implement the callback function is on the user side.

Simple form processing sample

The following example shows the handling of the output of HTML forms with your web server application. The example web page ExampleGET.htm implements a form with three inputs, two textfields and one button.

The HTML code of the the web page as it is added to the server is listed below:

<html>
  <head><title>embOS/IP web server form example</title></head>
  <body>
    <form action="" method="GET">
      <p>
        First name:
        <input name="FirstName"
                  type="text" size="30"
                  maxlength="30"
                  value="<!--#exec cgi="FirstName"-->"
         >
         <br>
        Last name:
        <input name="LastName"
                  type="text"
                  size="30"
                  maxlength="30"
                  value="<!--#exec cgi="LastName"-->"
         >
         <br>
         <input type="submit" value="Send">
      </p>
    </form>
  </body>
</html>

The action field of the form can specify a resource that the browser should reference when it sends back filled-in form data. If the action field defines no resource, the current resource will be requested again. If you request the web page from the embOS/IP web server and check the source of the page in your web browser, the CGI parts "<!--#exec cgi="FirstName"-->" and "<!--#exec cgi="LastName"-->" will be executed before the page will be transmit ted to the server, so that in the example the values of the value= fields will be empty strings.
strings.

<html>
  <head><title>embOS/IP web server form example</title></head>
  <body>
    <form action="" method="GET">
      <p>
        First name:
        <input name="FirstName"
                  type="text" size="30"
                  maxlength="30"
                  value=""
         >
         <br>
        Last name:
        <input name="LastName"
                  type="text"
                  size="30"
                  maxlength="30"
                  value=""
         >
         <br>
         <input type="submit" value="Send">
      </p>
    </form>
  </body>
</html>

To start form processing, you have to fill in the FirstName and the LastName field and click the Send button. In in the example, the browser sends a GET request for the resource referenced in the form and appends the form data to the resource name as an URL encoded string. The form data is separated from the resource name by "?". Every <name>=<value> pair is separated by "&".

For example, if you type in the FirstName field John and Doe in the LastName field and confirm the input by clicking the Send button, the following string will be transmitted to the server and shown in the address bar of the browser.

http://192.168.1.230/ExampleGET.htm?FirstName=John&LastName=Doe

Note: If you use POST as HTTP method, the name>=<value> pairs are not shown in the address bar of the browser. The <name>=<value> pairs are in this case included in the entity body.

The embOS/IP web server parses the form data. The <name> field specifies the name of a CGI function which should be called to process the <value> field. The server checks therefore if an entry is available in the WEBS_CGI array.

static const WEBS_CGI _aCGI[] = {
  {"FirstName", _callback_ExecFirstName},
  {"LastName", _callback_ExecLastName },
  {NULL}
};

If an entry can be found, the specified callback function will be called.
The callback function for the parameter FirstName is defined as follow:

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static char _acFirstName[12];

/*********************************************************************
*
*       _callback_FirstName
*/
static void _callback_ExecFirstName( WEBS_OUTPUT * pOutput, const char * sParameters, const char * sValue ) {
  if (sValue == NULL) {
    IP_WEBS_SendString(pOutput, _acFirstName);
  } else {
    _CopyString(_acFirstName, sValue, sizeof(_acFirstName));
  }
}

The function returns a string if sValue is NULL. If sValue is defined, it will be written into a character array. Because HTTP transmission methods GET and POST only transmit the value of filled input fields, the same function can be used to output a stored value of an input field or to set a new value. The example web page shows after entering and transmitting the input the new values of FirstName and LastName as value in the input fields.

The source of the web page as seen by the web browser is listed below:

<html>
  <head><title>embOS/IP web server form example</title></head>
  <body>
    <form action="" method="GET">
      <p>
        First name:
        <input name="FirstName"
                  type="text" size="30"
                  maxlength="30"
                  value="John"
         >
         <br>
        Last name:
        <input name="LastName"
                  type="text"
                  size="30"
                  maxlength="30"
                  value="Doe"
         >
         <br>
         <input type="submit" value="Send">
      </p>
    </form>
  </body>
</html>

Resource usage

The ROM usage depends on the compiler options, the compiler version and the used CPU. The memory requirements of the web server presented in the tables below have been measured on a system as follows: ARM7, IAR Embedded Workbench V5.11, Thumb mode, Size optimization.

Configuration used

#define WEBS_IN_BUFFER_SIZE         128
#define WEBS_OUT_BUFFER_SIZE        128
#define WEBS_TEMP_BUFFER_SIZE       128
#define WEBS_ERR_BUFFER_SIZE        (WEBS_OUT_BUFFER_SIZE / 2)
#define WEBS_AUTH_BUFFER_SIZE       32
#define WEBS_FILENAME_BUFFER_SIZE   32

ROM usage

Add-on ROM [Kbytes]
embOS/IP Web server 5.4

RAM usage

Task Description RAM [bytes]
ParentTask Listen for incoming connection 500

ChildTask

Handles a request 1800

The webserver requires at least 1 child task.
The approximately RAM usage for the web server can be calculated as follows:

RAM usage = 0.1 Kbytes + ParentTask + (NumberOfChildTasks * 1.8 Kbytes)

Example: Web server accepting up only 1 connection

RAM usage = 0.1 Kbytes + 0.5 Kbytes + (1 * 1.8 Kbytes)
RAM usage = 2.4 Kbytes

Example: Web server accepting up to 3 in parallel

RAM usage = 0.1 Kbytes + 0.5 Kbytes + (3 * 1.8 Kbytes)
RAM usage = 6.0 Kbytes

 

For more information download the windows trial version including manual.