The simple handler sample demonstrates
how to create an AppWeb handler.
AppWeb
has a modular architecture where each type of content is served by
dedicated "handlers". AppWeb analyses HTTP requests and routes parsed
requests to the relevant handler.
When built, the handler should be copied to the AppWeb
lib directory. The AppWeb configuration file will also need to be modified. See the
Configuration File section below for details.
Files
simpleHandler.h
Makefile
simpleHandler.cpp
Configuration File
To
load the module once built, you need to add the following line to your
AppWeb configuration file. Add this after the existing LoadModule
directives.
LoadModule simpleHandler ../../../lib/libsimpleHandler
Makefile
The Makefile will build on Windows or Linux. A Windows VS 6.0 project
file is also supplied.
Typical output from the Makefile build is listed below. This is the
output on a Windows system:
cl -o simpleHandler.dll simpleHandler.cpp -Zi -Od -D_NDEBUG -W3 -nologo -MDd -FD -DWIN -D_DLL -D_MT \
-D_WINDOWS -DWIN32 -D_WIN32_WINNT=0x500 -D_X86_=1 -D_CRT_SECURE_NO_DEPRECATE -D_USRDLL \
-I../../../include -LD ../../../bin/libappWeb.lib ws2_32.lib advapi32.lib user32.lib
Source
Code
The sample source includes two files:
simpleHandler.h
///
/// @file simpleHandler.h
/// @brief Header for the simpleHandler
///
// Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
//
////////////////////////////// Includes ////////////////////////////////
#ifndef _h_SIMPLE_HANDLER
#define _h_SIMPLE_HANDLER 1
#include "appWeb/appWeb.h"
/////////////////////////// Extern Definitions /////////////////////////
class SimpleHandler;
class SimpleHandlerService;
extern "C" {
extern int mprSimpleHandlerInit(void *handle);
};
////////////////////////////////////////////////////////////////////////
///////////////////////// SimpleHandlerModule //////////////////////////
////////////////////////////////////////////////////////////////////////
class SimpleHandlerModule : public MaModule {
private:
SimpleHandlerService *simpleService;
public:
SimpleHandlerModule(void *handle);
~SimpleHandlerModule();
};
////////////////////////////////////////////////////////////////////////
///////////////////////////// SimpleHandler ////////////////////////////
////////////////////////////////////////////////////////////////////////
class SimpleHandlerService : public MaHandlerService {
public:
SimpleHandlerService();
~SimpleHandlerService();
MaHandler *newHandler(MaServer *server, MaHost *host,
char *ext);
int setup();
};
class SimpleHandler : public MaHandler {
private:
public:
SimpleHandler(char *extensions);
~SimpleHandler();
MaHandler *cloneHandler();
int matchRequest(MaRequest *rq, char *uri,
int uriLen);
void postData(MaRequest *rq, char *buf, int buflen);
int run(MaRequest *rq);
int setup(MaRequest *rq);
};
////////////////////////////////////////////////////////////////////////
#endif // _h_SIMPLE_HANDLER
simpleHandler.cpp
///
/// @file simpleHandler.cpp
/// @brief Create a simple AppWeb dynamically loadable module
///
/// This sample demonstrates creating a simple module that can be
/// dynamically or statically loaded into the AppWeb server. Modules
/// can be URL handlers, Scripting Engines or just extension APIs to
/// extend the AppWeb server.
///
// Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
//
////////////////////////////// Includes ////////////////////////////////
#define IN_SIMPLE_HANDLER 1
#include "appWeb/appWeb.h"
#include "simpleHandler.h"
////////////////////////////////////////////////////////////////////////
////////////////////////// SimpleHandlerModule /////////////////////////
////////////////////////////////////////////////////////////////////////
//
// Module entry point. This is only called when the module is loaded
// as a DLL.
//
int mprSimpleHandlerInit(void *handle)
{
mprLog(0, "In SimpleHandlerInit()\n");
new SimpleHandlerModule(handle);
return 0;
}
////////////////////////////////////////////////////////////////////////
///
/// Constructor. Called either above when the DLL is loaded or from the
/// application main if loading statically.
///
SimpleHandlerModule::SimpleHandlerModule(void *handle) :
MaModule("simpleHandler", handle)
{
mprLog(0, "In SimpleHandlerModule()\n");
//
// Create the handler service (one per application) and insert into
// the HTTP service.
//
simpleService = new SimpleHandlerService();
// maGetHttp()->insertHandlerService(simpleService);
}
////////////////////////////////////////////////////////////////////////
///
/// Module destructor
///
SimpleHandlerModule::~SimpleHandlerModule()
{
mprLog(0, "In ~SimpleHandlerModule()\n");
delete simpleService;
}
////////////////////////////////////////////////////////////////////////
///////////////////////// SimpleHandlerService /////////////////////////
////////////////////////////////////////////////////////////////////////
///
/// Constructor for the SimpleHandler service. An instance is created
/// for each host (default and virtual).
///
SimpleHandlerService::SimpleHandlerService() :
MaHandlerService("simpleHandler")
{
mprLog(0, "In SimpleHandlerService()\n");
}
////////////////////////////////////////////////////////////////////////
///
/// Destructor for the SimpleHandler.
///
SimpleHandlerService::~SimpleHandlerService()
{
mprLog(0, "In ~SimpleHandlerService()\n");
}
////////////////////////////////////////////////////////////////////////
///
/// Setup the SimpleHandler service. One-time setup for a given host.
///
int SimpleHandlerService::setup()
{
mprLog(0, "In SimpleHandlerService:setup()\n");
return 0;
}
////////////////////////////////////////////////////////////////////////
///
/// New Handler factory. Create a new SimpleHandler for an incoming
/// HTTP request for a given server
///
MaHandler *SimpleHandlerService::newHandler(MaServer *server,
MaHost *host, char *extensions)
{
mprLog(0, "In SimpleHandlerService:newHandler()\n");
return new SimpleHandler(extensions);
}
////////////////////////////////////////////////////////////////////////
///////////////////////////// SimpleHandler ////////////////////////////
////////////////////////////////////////////////////////////////////////
///
/// A SimpleHandler is created for each incoming HTTP request. We tell
/// the Handler base class that we will be a terminal handler. Handlers
/// can be non-terminal where they can modify the request, but not
/// actually handle it. This handler only accepts "GET" requests.
///
SimpleHandler::SimpleHandler(char *extensions) :
MaHandler("simpleHandler", extensions,
MPR_HANDLER_GET | MPR_HANDLER_TERMINAL)
{
mprLog(0, "In SimpleHandler::simpleHandler()\n");
}
////////////////////////////////////////////////////////////////////////
///
/// Destructor for the SimpleHandler
///
SimpleHandler::~SimpleHandler()
{
mprLog(0, "In SimpleHandler::~simpleHandler()\n");
}
////////////////////////////////////////////////////////////////////////
///
/// For maximum speed in servicing requests, we clone a pre-existing
/// handler when an incoming request arrives.
///
MaHandler *SimpleHandler::cloneHandler()
{
SimpleHandler *ep;
mprLog(0, "In SimpleHandler::cloneHandler()\n");
ep = new SimpleHandler(extensions);
return ep;
}
////////////////////////////////////////////////////////////////////////
///
/// Called to setup any data structures before running the request
///
int SimpleHandler::setup(MaRequest *rq)
{
mprLog(0, "In SimpleHandler::setup()\n");
return 0;
}
////////////////////////////////////////////////////////////////////////
///
/// Called to see if this handler should process this request.
/// Return TRUE if you want this handler to match this request
///
int SimpleHandler::matchRequest(MaRequest *rq, char *uri, int uriLen)
{
MprStringData *sd;
int len;
//
// Example custom matching.
// For example, to match against URLs that start with "/myUrl":
//
if (strncmp(uri, "/myUrl", 6) == 0) {
return 1;
}
//
// Match against extensions defined for this handler
//
sd = (MprStringData*) extList.getFirst();
while (sd) {
len = strlen(sd->string);
if (uriLen > len &&
strncmp(sd->string, &uri[uriLen - len], len) == 0) {
return 1;
}
sd = (MprStringData*) extList.getNext(sd);
}
//
// No match. The next handler in the chain will match.
//
return 0;
}
////////////////////////////////////////////////////////////////////////
///
/// Receive any post data. Will be called after the run() method has
/// been called and may be called multiple times. End of data is when
/// remainingContent() == 0.
///
void SimpleHandler::postData(MaRequest *rq, char *buf, int len)
{
mprLog(0,
"SimpleHandler::postData: postData %d bytes, remaining %d\n",
rq->getFd(), len, rq->getRemainingContent());
}
////////////////////////////////////////////////////////////////////////
///
/// Run the handler to service the request
///
int SimpleHandler::run(MaRequest *rq)
{
MprFileInfo info;
MaDataStream *dynBuf;
char *fileName;
int flags;
hitCount++;
flags = rq->getFlags();
dynBuf = rq->getDynBuf();
//
// Set a default "success" response with HTML content.
//
rq->setResponseCode(200);
rq->setResponseMimeType("text/html");
//
// If we are generating dynamic data, we should add a cache control
// header to the response.
//
rq->setHeaderFlags(MPR_HTTP_DONT_CACHE);
//
// Open a document to return to the client
//
fileName = rq->getFileName();
if (rq->openDoc(fileName) < 0) {
rq->requestError(404, "Can't open document: %s", fileName);
return MPR_HTTP_HANDLER_FINISHED_PROCESSING;
}
mprLog(4, "%d: serving: %s\n", rq->getFd(), fileName);
//
// Insert the document DataStream and define the file size
// Alternatively you could dynamically generate data and use the
// Dyn buffer.
//
if (!(flags & MPR_HTTP_HEAD_REQUEST)) {
rq->insertDataStream(rq->getDocBuf());
rq->statDoc(&info);
rq->getDocBuf()->setSize(info.size);
}
//
// Flush in the background
//
rq->flushOutput(MPR_HTTP_BACKGROUND_FLUSH, MPR_HTTP_FINISH_REQUEST);
return MPR_HTTP_HANDLER_FINISHED_PROCESSING;
}
////////////////////////////////////////////////////////////////////////