Simple Handler Sample in C++

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
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

Source Code

The sample includes four files:

simpleHandler.h

///
/// @file simpleHandler.h
/// @brief Header for the simpleHandler
///
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Mbedthis Software LLC, 2003-2004. All Rights Reserved.
// The latest version of this code is available at https://mbedthis.com
//
////////////////////////////// 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

//
// Copyright (c) Mbedthis Software LLC, 2003-2004. All Rights Reserved.
//
/// @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.
///

////////////////////////////// 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 till
/// the Handler base class that we need an environment and we will be
/// a terminal handler. Handlers can be non-terminal where they can
/// modify the request, but not actually handle it.
///

SimpleHandler::SimpleHandler(char *extensions) :
MaHandler("simpleHandler", extensions,
MPR_HANDLER_NEED_ENV | 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);
ep->flags |= MPR_ESP_CLONED;
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.
///

int SimpleHandler::matchRequest(MaRequest *rq, char *uri, int uriLen)
{
//
// Return TRUE if you want this handler to match this request
// For example, to match against URLs that start with "/myUrl":
//
if (strncmp(uri, "/myUrl", 6) == 0) {
return 1;
}
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->setContentType("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;
}


////////////////////////////////////////////////////////////////////////


© Mbedthis Software LLC, 2003-2204. All rights reserved. Mbedthis is a trademark of Mbedthis Software LLC.