NAME

Tiny HTTP Server - thttpd

SYNOPSIS

#include <sys.h>

#include <stdio.h>

#include <tcpinit.h>

#include <sys/socket.h>

#include <thttpd.h>



thttpd_main((char *)httpdconf_name);

DESCRIPTION

thttpd is simple of use and fast solution for adding HTTP support to your application.

The thttpd server provides the capability to provide the following services and support



Thttpd server requires for work TCP and FatFs/Fsys servers. This servers must be started before run thttpd.

Thttpd starting by command:

thttpd_main((char *)httpdconf_name);

Where httpdconf_name is a full configuration file name. This file holds basic configuration parameters for thttp and has another structure:

Pram:value

Pram:value

...

Pram:value

Param

Description

Sample

server_software

software product name

UnisonHttpd

http_index

default start page

index.html

http_root

server root folder

/dev/rd/thttp/

http_port

default http port

80

server_name

server name, used by http protocol

Thttpd server

host_name

host name, used by http protocol

Myhost

cgi_ena

enable cgi handling (0 or 1)

1

data_timeout

watchdog to handle physical link loss

20

keepalive_timeout

timeout to keep socket opened, after handling browser requests

30

Login and Authentication Support

Thttpd server can provide access to some pages by password.

To setup the login information, users need to do the following:

Example:

#include <login.h>
set_loginfile(htpasswd_name); //htpasswd_name - full path to .htpasswd file
init_login_table(htpasswd_name);


To add or delete new user run:

add_user( "username", "passwd" );
delete_user( "username");

Now if client access to protected files he must enter valid password and username. Server can support many different users

CGI Support

If application need to have CGI getaway support you need:

Example:

register_cgi_handler("name", "URL_path", cgi_handler_funk);

Parametrs:

It is possible to register a few cgi handlers in system. It is also possible to register one handler for different addresses.

Example:

register_cgi_handler ("test1", "cgi-bin/userI1.cgi", UI_cgi_handler);
register_cgi_handler ("test2", "cgi-bin/userI2.cgi", UI_cgi_handler);
register_cgi_handler ("test3", "cgi-bin/userI3.cgi", ABC_cgi_handler);


In this way the server will use one handler UI_cgi_handler for addresses

XXX/cgi-bin/userI1.cgi and XXX/cgi-bin/userI2.cgi. It will use a completely different handler ABC_cgi_handler for XXX/cgibin/userI3.cgi

To delete registerd cgi handler run del_cgi_handler

Example:

del_cgi_handler(“name”);

To handle all user data which is input from the Browser a next parameters list is passed into the cgi-handler.

int cgi_handler (char * path , char ** argv , char ** envp, int fd);

*path – path for which this handler is called. For instance, "cgi-bin/userI.cgi"

**argv – pointer array to parameters strings (to date it is 2 max)

argv[0] – called file name. For instance "userI.cgi"

argv[1] – If parameters are passed using method GET, then in argv[1] string with this parameters is passed, else (null)

**envp – pointers array to strings, which is containing information, passed by Browser using http headers (according to CGI standard). This array can contain variable numbers of elements, with the array ended by '\0'.

Example:

HTTP_USER_AGENT=Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10
HTTP_HOST=192.168.16.201
HTTP_ACCEPT=text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/xxbitmap,*/*;q=0.1
HTTP_ACCEPT_LANGUAGE=ru-RU,ru;q=0.9,en;q=0.8
HTTP_ACCEPT_CHARSET=iso-8859-1, utf-8, utf-16, *;q=0.1
HTTP_ACCEPT_ENCODING=deflate, gzip, x-gzip, identity, *;q=0
HTTP_REFERER=http://192.168.16.201/
HTTP_CONNECTION=Keep-Alive, TE
HTTP_TE=deflate, gzip, chunked, identity, trailers
HTTP_CONTENT_LENGTH=43
HTTP_CONTENT_TYPE=application/x-www-form-urlencoded
SERVER_NAME=Myhost
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=POST
SCRIPT_NAME=/cgi-bin/userI.cgi
SCRIPT_FILENAME=cgi-bin/userI.cgi
SERVER_SOFTWARE=UnisonHttpd
REQUEST_URI=cgi-bin/userI.cgi
CONTENT_TYPE=application/x-www-form-urlencoded
CONTENT_LENGTH=43
SERVER_PORT=1568
REMOTE_ADDR=192.168.18.1

fd socket ID, from which the handler will read data and where the handler will write the newly created page

In summary, the cgi_handler function inputs the parameters, processes the input arguments and creates a new page which is streamed back to the browser to update the user.

You can parse input parameters **envp by use function getenv(“header name”, envp); and getparam(str, "field=");

Example:

env = getenv("REQUEST_METHOD", envp);
if (strcmp(env, "POST")==0) {                           //metod == "POST"
        size = atoi(getenv("CONTENT_LENGTH", envp));    //getting recived data size
        pos = recv(fd, str, size, 0);                           //reciving data from stream
        str[pos] = '\0';
}else { //metod == "GET"
        env = getenv("QUERY_STRING", envp); //Reading query string sended by GET metod
        strcpy(str,env);
}
name = getparam(str,"name_field="); //get entered "user Name"
age = getparam(str,"age_field="); //get entered "user Age"



Note: These CGI handlers must be compiled into the executable as part of the image. This means that changes to the web pages create a need to update the CGI handlers if the updates are more than cosmetic, or in other words, new variables are added.



EXAMPLE

pthread_t tid;
pthread_attr_t  attr;
struct fsysinit  fsysinit;
struct sched_param myNewPriority;
int mkfs_status, mount_status;
int fd;

xprintf("Start Main\n");

/*FSYS Initialization*/
fsysinit.fsi_msgsize = sizeof(struct fsysinit);
fsysinit.fsi_nclones = 1;
fsysinit.fsi_datalog = 0x3;
fsysinit.fsi_nbuffers = 4; /* num of disk buffers (cache size) */
fsysinit.fsi_maxopen = 2; /* max num of open files */
fsysinit.fsi_blocksize = 256;

// set up stack size and priority for main fsys threads and all clones
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, FSYSSTACKSIZE);
myNewPriority.sched_priority = FSYSPRIO;
pthread_attr_setschedparam(&attr, &myNewPriority);

if(!pthread_create(&tid, &attr,(void*(*)(void *))&_file_server, (char*)&fsysinit))
{
        if(!dir_register(FSYS_DIRECTORY, tid, TYPE_SERVER))
        {
                xprintf("..Unable to register name of File Server\n..");
                xprintf("..Required resource not present - aborting..\n");

                pthread_exit((void*)1);
        }
}
else
{
        xprintf("..Unable to create File Server..\n");
        xprintf("..Required resource for program not present - aborting..\n");
        pthread_exit((void*)1);
}
xprintf("..File server is now created.\n..");
xprintf("\n..Attempting to mount it...\n");

if((mount_status = mount(DEVICE_NO, FSYS_MOUNT, 0)) == -1) {
        xprintf("..Unable to mount flash disk. errno=%d\n", errno);
        xprintf("..Please fix me\n..");
        pthread_exit((void*)1);
}

xprintf("..done fsys initialization..\n");

set_loginfile(htpasswd_name);    //set login and pass to access to files in this dir
init_login_table(htpasswd_name);
add_user( "root", "root" );

/* make virtual link to user handler call address
 * http://xxx.xxx.xxx.xxx/cgi-bin/userI.cgi
 * will run UI_cgi_handler();
 */
register_cgi_handler("test", "cgi-bin/userI.cgi", UI_cgi_handler);

/* Start tcpd server*/
xprintf("\n--- Start tcpd ---\n");

myNewPriority.sched_priority = TCPRIO;
pthread_attr_setschedparam(&attr, &myNewPriority);
pthread_attr_setstacksize(&attr, TCPSTACKSIZE);
if(pthread_create(&tid, &attr, &tcp_shell, 0)!=0)
{
        xprintf("pthread_create = %d\n", errno);
        pthread_exit(0);
}

if(dir_register("/dev/tcpd", tid, TYPE_SERVER)==0)
{
        xprintf("dir_register = %d\n", errno);
        pthread_exit(0);
}

/* Start THTTP server */
xprintf("\n--- Start HTTP server ---\n");
// set up stack size and priority for main THTTP thread
pthread_attr_setstacksize(&attr, THTTPSTACKSIZE);
myNewPriority.sched_priority = THTTPPRIO;
pthread_attr_setschedparam(&attr, &myNewPriority);

if(pthread_create(&tid, &attr,(void*(*)(void *))&thttp_shell, NULL)!=0)
{
        xprintf("..Unable to create THTTP Server..\n");
        pthread_exit((void*)1);
}


THREAD tcp_shell(void * args)
{
        tcpd((char *)&etherinit, 0);
        return (THREAD)0;
}


THREAD thttp_shell(void * args)
{
        thttpd_main((char *)httpdconf_name);
        return (THREAD)0;       
}

NOTES

There is demo available for the Unison and DSPnano thttpd which are found in installdir/demos which provide examples of using the server with simple page, password protected and CGI generated pages.

SEE ALSO

ppp server FatFS server login




< Copyright Rowebots Research Inc. and Multiprocessor Toolsmiths Inc. 1987-2011 >