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) Embedthis Software LLC, 2003-2009. 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) Embedthis Software LLC, 2003-2009. 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;
}
////////////////////////////////////////////////////////////////////////