Creating HTML User Interfaces for Server Programs 
by Michael Janulaitis

Example 1: 

LoadModule acme_module modules/AcmeModule.dll
<LocationMatch "/[Aa][Cc][Mm][Ee]">
SetHandler acme-handler
</LocationMatch>
acmeServerHost localhost
acmeServerPort 28500


Listing One
/* The sample code provided is for Windows only */
/* main.c */

#include <winsock2.h>
#include <conio.h>
#include <stdio.h>
#include "acmeprotocol.h"

/* user entry which contains a key and a name */
typedef struct {
    DWORD key;
    char *user;
    char *pswd;
}USER_T;
/* static list that contains three users */
static USER_T users[] = {
    { 0xFFFFFFFF, "Manny", "manny" },
    { 0xFFFFFFFF, "Moe", "moe" },
    { 0xFFFFFFFF, "Jack", "jack" }
};
int main(int argc, char **argv) {
    ACMEPROTOCOL_T command, response;
    BOOL bQuit = FALSE;
    BYTE *pbt;
    char input, packet[256], *pswd, *user;
    DWORD key, localkey = 0, *pdw;
    int fromlen, i, rc;
    FD_SET fdsErr, fdsRead, fdSet;
    struct sockaddr_in  from, local;
    SOCKET s, msgsock;
    SYSTEMTIME ts;
    struct timeval t = { 1, 0};
    WORD *pw;
    WSADATA wsadata;
    /* create the server */
    if (WSAStartup(MAKEWORD(2,2), &wsadata))
        return -1;
    local.sin_family = AF_INET;
    local.sin_port = htons(28500);
    local.sin_addr.s_addr = htonl(INADDR_ANY);
    s = socket(AF_INET, SOCK_STREAM, 0);
    if(INVALID_SOCKET == s) {
        WSACleanup(); return -1;
    }
    if (bind(s,(struct sockaddr*)&local,sizeof(local) ) == SOCKET_ERROR)
        bQuit = TRUE;    
    if (listen(s,SOMAXCONN) == SOCKET_ERROR)
        bQuit = TRUE;    
    FD_ZERO(&fdSet);
    FD_SET(s, &fdSet);
    while(!bQuit) {
        while(!kbhit()) {         
            memcpy((void*)&fdsRead,(void*)&fdSet, sizeof(fd_set));
            memcpy((void*)&fdsErr, (void*)&fdSet, sizeof(fd_set));
            rc = select(0, &fdsRead, NULL, &fdsErr, &t);
            if (SOCKET_ERROR == rc) {
                bQuit = TRUE;
                break;
            }
            if (!rc)
                continue;            
            if (FD_ISSET(s, &fdsErr)) {
                bQuit = TRUE;
                break;
            }
            if (!FD_ISSET(s, &fdsRead))
                continue;
            fromlen = sizeof(from);
            msgsock = accept(s,(struct sockaddr*)&from, &fromlen);
            if (msgsock == INVALID_SOCKET) {
                bQuit = TRUE;
                break;
            }
            /* Get the command.  Note that the data must be sent in one 
            packet otherwise this program will fail. This program also 
            assumes the correct data is sent. You will need to write a packet 
            handler to deal with these issues */
            rc = recv(msgsock,packet,sizeof(packet),0 );
            if (SOCKET_ERROR != rc && rc && 
                rc >= sizeof(ACMEPROTOCOL_T) + sizeof(DWORD)) {
                /* handle the command */
                pbt = packet;
                pw = (WORD*)pbt;
                command.cmd = (WORD)ntohs(*pw);
                pbt += sizeof(WORD);
                pw = (WORD*)pbt;
                command.status = (WORD)ntohs(*pw);
                pbt += sizeof(WORD);
                pdw = (DWORD*)pbt;
                command.size = (DWORD)ntohl(*pdw);
                pbt += sizeof(DWORD);
                pdw = (DWORD*)pbt;
                key = (DWORD)ntohl(*pdw);
                pbt += sizeof(DWORD);

                response.cmd = command.cmd;
                response.status = 0;
                response.size = 0;
                switch (command.cmd)
                {
                case CMD_LOGIN:
                    user = pbt;   /* protocol handler required */
                    pbt += strlen(user) + 1;
                    pswd = pbt;   /* protocol handler required */
                    for (i = 0; i < 3; i++) {
                        if (!strcmp(users[i].user, user)) {
                            if (!strcmp(users[i].pswd, pswd)) {
                                users[i].key = ++localkey;
                                pbt = packet;
                                pbt += sizeof(ACMEPROTOCOL_T);
                                pdw = (DWORD*)pbt;
                                *pdw = htonl(users[i].key);
                                response.size = sizeof(DWORD);
                                response.status = 1;
                            }
                            break;
                        }
                    }
                    break;
                case CMD_LOGOUT:
                    for (i = 0; i < 3; i++) {
                        if (users[i].key == key) {
                            users[i].key = 0xFFFFFFFF;
                            response.status = 1;
                            break;
                        }
                    }
                    break;
                case CMD_GETTIME:
                    for (i = 0; i < 3; i++) {
                      if (users[i].key == key) {
                        GetSystemTime(&ts);
                        pbt = packet;
                        pbt += sizeof(ACMEPROTOCOL_T);
                        _snprintf(pbt, 
                          sizeof(packet) - sizeof(ACMEPROTOCOL_T), 
                          "%02d:%02d:%02d", ts.wHour, ts.wMinute, ts.wSecond);
                        pbt[sizeof(packet) - sizeof(ACMEPROTOCOL_T) - 1] = 0;
                        response.size = strlen(pbt) + 1;
                        response.status = 1;
                        break;
                      }
                    }
                    break;
                }
                pbt = packet;
                pw = (WORD*)pbt;
                *pw = htons(response.cmd);
                pbt += sizeof(WORD);
                pw = (WORD*)pbt;
                *pw = htons(response.status);
                pbt += sizeof(WORD);
                pdw = (DWORD*)pbt;
                *pdw = htonl(response.size);
                pbt += sizeof(DWORD);
                send(msgsock,packet,sizeof(ACMEPROTOCOL_T) + response.size,0);
            }
            closesocket(msgsock);
        }
        input = getch();
        if (input == 'q')
            break;
    }
    closesocket(s); 
    WSACleanup(); 
    return 0;
}
/* acmdprotocol.h */
#ifndef ACMEPROTOCOL_H
#define ACMEPROTOCOL_H
typedef struct {
    WORD cmd;
    WORD status;
    DWORD size;
}ACMEPROTOCOL_T;
typedef enum {
    CMD_LOGIN, CMD_LOGOUT, CMD_GETTIME,
}CMD;
#endif


Listing Two
static char g_host[256];
static WORD g_port = 28500;
BOOL CAcmeISAPIFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
{
    // Call default implementation for initialization
    CHttpFilter::GetFilterVersion(pVer);
    // Clear the flags set by base class
    pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;
    // Set the flags we are interested in
    pVer->dwFlags |= SF_NOTIFY_ORDER_LOW | SF_NOTIFY_SECURE_PORT |
                     SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_PREPROC_HEADERS;
    // Load description string
    TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
    ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
            IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
    _tcscpy(pVer->lpszFilterDesc, sz);
    DWORD   port, type, size;
    HKEY    hKey; 
    g_host[0] = 0;
    // Open the registry
    if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                               _T("software\\acme"), 0, KEY_READ, &hKey))
        return FALSE;
    // Get the server application host
    size = sizeof(g_host);
    if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("host"), 
                                       0, &type, (BYTE*)&g_host, &size)) {
        RegCloseKey(hKey);
        return FALSE;
    }
    // Get the mas port
    size = sizeof(port);
    if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("port"), 
                                      0, &type, (BYTE*)&port, &size)) {
        RegCloseKey(hKey);
        return FALSE;
    }
    g_port = (WORD)port;
    // Close the registry
    RegCloseKey(hKey);     
    return TRUE;
}

Listing Three
DWORD CAcmeISAPIFilter::OnPreprocHeaders(CHttpFilterContext* pfc, 
                                    PHTTP_FILTER_PREPROC_HEADERS pHeaders) 
{
    TCHAR url[256], newurl[256], *test;
    DWORD size = sizeof(url);
    if (pHeaders->GetHeader(pfc->m_pFC,_T("URL"),url,&size)) {
        test = _tcsstr(url, _T("/acme"));
        if (test) { 
            test += _tcslen(_T("/acme"));
            if (test[0]) {
                _sntprintf(newurl, 256, _T("/Scripts/AcmeISAPI.dll%s"), test);
                newurl[255] = 0;
            } else
                _tcscpy(newurl, _T("/Scripts/AcmeISAPI.dll"));
            pHeaders->SetHeader(pfc->m_pFC, _T("URL"), newurl);
        }
    }
    return CHttpFilter::OnPreprocHeaders(pfc, pHeaders);
}





5

