Setting Up an Embedded Web Server

This chapter includes:

Neutrino ships with Slinger, a very small web server optimized for embedded applications. Since it supports Common Gateway Interface (CGI) 1.1, HTTP 1.1, and dynamic HTML (via SSI commands), it lets you easily add embedded HTTP services and dynamic content to your embedded applications.

For example, you can write an application that monitors a printer and uses Slinger to update a remote client that displays the printer's status:

Data server example

Where should you put the files?

Before you start the Slinger web server and begin creating your web pages, you need to determine what directory structure is appropriate, and where you should put your files.


Caution: Be careful not to place your files in a location where your system is open to outsiders, thereby exposing your system to undue risk. For example, don't place your CGI scripts in the same directory as your regular system binaries, because doing so could let people run any command on the machine that supports your web server.

Use these environment variables to configure Slinger:

HTTPD_ROOT_DIR
The name of the directory where Slinger looks for data files. The default is /usr/local/httpd.
HTTP_ROOT_DOC
The name of the root document. When a web client requests the root document, HTTPD_ROOT_DOC is appended to HTTPD_ROOT_DIR to build the full pathname of the root document. The default is index.html.

For example, if HTTPD_ROOT_DOC is defined as index.html, and HTTPD_ROOT_DIR is defined as /usr/www, Slinger appends index.html to /usr/www to build /usr/www/index.html.

Once you've decided on a directory structure, you need to export these environment variables before starting Slinger:

export HTTPD_ROOT_DIR=/usr/local/httpd
export HTTPD_ROOT_DOC=index.html

For information on setting environment variables when you login to your machine, see Configuring Your Environment.

Running Slinger

To run Slinger, simply type:

slinger &

Note: The Slinger web server communicates over TCP sockets, so you need to have socket runtime support. This means you need to have a TCP/IP stack running. For more information, see the TCP/IP Networking chapter in this guide.

The Slinger server listens on the TCP port 80. Since this port number is less than 1024, Slinger needs to run as root. As soon as it has attached to the HTTP port, it changes itself to run as user ID -2, by calling (setuid (-2)).


Many embedded servers force the user to relink the server in order to add pages, which compromises reliability because vendor and user code compete in a shared memory space. Despite its size, Slinger provides enough functionality to support accessing generated (dynamic) HTML via CGI or SSI.

Dynamic HTML

The embedded web server lets you use create dynamic HTML in various ways:

CGI method

The embedded web server supports the Common Gateway Interface (CGI) 1.1, a readily available means of handling dynamic data. The downside of CGI is that it's resource-heavy because it often involves an interpreted language.

If you're using the CGI method, you need to decide where to locate your cgi-bin directory, which contains all your CGI scripts.

To tell the embedded web server that you want to use the CGI method, you need to use the HTTPD_SCRIPTALIAS environment variable to tell it where to find the CGI scripts and executables. For example:

export HTTPD_SCRIPTALIAS=/usr/www/cgi-bin

If you define HTTPD_SCRIPTALIAS, anybody can run scripts or processes that reside in that directory on your machine. Therefore, make sure you create a separate directory for these scripts to reside in. Not defining HTTPD_SCRIPTALIAS turns CGI functionality off, causing all CGI requests to fail.


Caution: Don't use /bin or /usr/bin as your CGI directory. Don't place any sensitive files in the cgi-bin directory, because doing so exposes them to anyone who uses the web server.

Make sure that the files in the cgi-bin directory can be executable by anybody, but modifiable only by root, by running chmod 755 on the files in the directory.


For example, suppose HTTPD_SCRIPTALIAS contains /usr/www/cgi-bin as the name of the directory. If Slinger gets a request for the resource www.qnx.com/cgi-bin/get_data.cgi/foo, the get_data.cgi script found in /usr/www/cgi-bin is executed, and foo is sent as pathname information to get_data.cgi. The foo directory is stored in the PATH_INFO environment variable, which is used to send extra path information.

Slinger sets several environment variables, which can be used by CGI scripts. For more information, see slinger in the Utilities Reference.

SSI method

Server Side Includes (SSI) is a type of command language that can be embedded in HTML files. With SSI, you can add dynamic content to your HTML. Slinger uses the PATH and CMD_INT environment variables to provide information to the SSI command, exec. Using dynamic HTML, clients can offer interactive realtime features on their web pages.

Clients can create dynamic HTML by placing SSI tokens in the HTML code of their web pages. The SSI token contains a command that's handled by Slinger. While transmitting the HTML code, Slinger replaces a token with HTML data, based on the tag contained in the SSI token.

For example, the embedded server can:

For Slinger to process SSI tokens, the HTML file must have .shtml as its file extension.

You can use SSI tags to interact with a data server.

Syntax for SSI Commands

Here are some examples of SSI commands that you can use in your scripts.

<!-- #echo var="DATE_LOCAL" -->
Display the time and date.
<!-- #echo var="DATE_GMT" -->
Display the time and date using Greenwich Mean Time.
<!-- #echo var="REMOTE_ADDR" -->
Display the visitor's IP address.
<!-- #echo var="HTTP_USER_AGENT" -->
Display the visitor's browser information.
<!-- #config timefmt = "%A %B %d, %y" --> This file last modified <!-- #echo vars="LAST_MODIFIED"-->
Display the date the page was last modified.
<!-- #include virtual = "myfile.shtml" -->
Include the file myfile.shtml as inline HTML in the web page.
<!-- #exec cgi = "counter.pl" -->
Execute the CGI script, counter.pl, and put the output on the web page.
<!-- #config cmdecho = "on" --><!--# exec cmd = "cd /tmp; ls" -->
Display the contents of the /tmp directory on the web page.

Data server method

You can also handle dynamic HTML by using a data server process, ds. A data server lets multiple threads share data without regard for process boundaries. Since the embedded web server supports SSI, we've extended this support by adding the ability to talk to the data server.

Now you can have a process updating the data server about the state of a hardware device while the embedded web server accesses that state in a decoupled but reliable manner.

For more information about the data server process and an example device monitoring application, see the documentation for ds in the Utilities Reference.

Security precautions

When you choose the directory for your data files, we recommend that you:

If you configure Slinger to support CGI:

Don't expose your machine to undue risk. Make sure that:

These precautions will help prevent anybody from giving your machine a new password file or tampering with your web pages.

For more information, see the Securing Your System chapter in this guide.

Examples

Configuration

We recommend that you put your documents and scripts in separate directories. In this example, the documents are in the /usr/local/httpd directory, the root document is index.html, and the CGI scripts are in /usr/www/cgi-bin.

export HTTPD_ROOT_DIR=/usr/local/httpd
export HTTPD_ROOT_DOC=index.html
export HTTPD_SCRIPTALIAS=/usr/www/cgi-bin
slinger &

The following example is the wrong way to configure Slinger. Anyone can download the scripts because the documents and scripts are in the same directory:

export HTTPD_ROOT_DIR=/usr/www
export HTTPD_ROOT_DOC=index.html
export HTTPD_SCRIPTALIAS=/usr/www
slinger &

To configure Slinger to start with SSI and enable debugging, you can use these commands:

export HTTPD_ROOT_DIR=/usr/local/httpd
export HTTPD_ROOT_DOC=index.shtml
export HTTPD_SCRIPTALIAS=/usr/www/cgi-bin
slinger -des&

Script

Here are two examples of a simple CGI script that displays a randomly selected image on a web page. The same script is presented here in C and perl, so that you can see how to implement scripts in either language.

You should put the executable C program (rand_images.cgi) and the perl script (rand_images.pl) in /usr/www/cgi-bin. Use chmod to make sure that both files have 755 permissions.

The images that they access are actually located in /usr/local/httpd/images. The web pages access the images in their local directory; the CGI script just figures out which one it wants to load.

To run these scripts from a web page, use the following HTML with SSI commands:

<H2>Here is a random image</H2>
<P>
Perl Script: <!--#exec cgi="rand_images.pl" --><BR>
C Program: <!--#exec cgi="rand_images.cgi" --><BR>

rand_images.c

To compile this application, run:

cc -o rand_images.cgi rand_images.c

Listing:

/* This program selects a random number and then
   chooses an image, based on that number. This
   allows the image to change each time the webpage
   is loaded.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* set variables */

char *dir = "/images/";
char *files[] ={"file1.jpg", "file2.jpg",
                "file3.jpg", "file4.jpg",
                "file5.jpg"};
int num;
int size;

int main()
{
  size = sizeof (files) / sizeof (files[0]);
  srand( (int)time(NULL) );  
  num = ( rand() % 4 );

  /* Print out head with Random Filename and
     Base Directory */

  printf("<img src=\"%s%s\" alt=%s border=1 >\n<BR>",
         dir, files[num], files[num]);
  printf("Location: %s%s\n\n<BR>",dir, files[num]);
  return (0);
}

rand_images.pl

#!/usr/bin/perl

# This script selects a random number and then
# chooses an image, based on that number. This
# allows the image to change each time the webpage 
# is loaded.

# set variables
  $dir = "/images/";
  @files = ("file1.jpg", "file2.jpg", "file3.jpg",
            "file4.jpg", "file5.jpg");

srand(time ^ $$);
$num = rand(@files); # Pick a Random Number

# Print Out Header With Random Filename and Base
# Directory

print "<img src=\"$dir$files[$num]\"
      alt=$files[$num] border=1 >\n<BR>";
print "Location: $dir$files[$num]\n\n<BR>";