EHS Embedded HTTP Server  1.5.0.132
ehs_test.cpp

Multiple instances serving different URI paths.This example shows, how multiple EHS instances can handle different URI paths. Furthermore, handling of cookies is demonstrated as well.

/* $Id: ehs_test.cpp 70 2011-12-12 17:11:44Z felfert $
 *
 * EHS is a library for embedding HTTP(S) support into a C++ application
 *
 * Copyright (C) 2004 Zachary J. Hansen
 *
 * Code cleanup, new features and bugfixes: Copyright (C) 2010 Fritz Elfert
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1 as published by the Free Software Foundation;
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    This can be found in the 'COPYING' file.
 *
 */

#include <ehs.h>

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include "common.h"

using namespace std;

class tester : public EHS
{
    protected:
        virtual ResponseCode HandleRequest(HttpRequest *, HttpResponse *);

    public:

        tester(string file, int delay = 0):
            EHS(), m_nDelay(delay), m_oInfile(file.c_str())
        {
            cout << "loading file '" << file << "'" << endl;
            if (m_oInfile.fail()) {
                throw runtime_error("Could not open file");
            }
        }

    private:
        // delay
        int m_nDelay;

        // our source file
        ifstream m_oInfile;
};

static int nRequests = 0;
static pthread_mutex_t oRequestMutex = PTHREAD_MUTEX_INITIALIZER;

ResponseCode tester::HandleRequest(HttpRequest *request, HttpResponse *response)
{

    pthread_mutex_lock(&oRequestMutex);
    int nMyRequest = ++nRequests;
    pthread_mutex_unlock(&oRequestMutex);

    if (0 == (nMyRequest % 1000)) {
        cerr << "[" << nMyRequest << "]" << endl;
    }

    char buf[5000];

    sleep (m_nDelay);
    m_oInfile.getline(buf, 4999);
    if (m_oInfile.eof()) {
        // At end of file start from beginning
        m_oInfile.seekg(0);
    }

    string sCopy(buf);
    string sBody(buf);

    sBody.append("<br>previous line: ").append(request->Cookies("ehs_test_cookie"));
    response->SetBody(sBody.c_str(), sBody.length());

    // throw in a cookie here, just to show how it's done
    CookieParameters oCP;
    string sCookieName("ehs_test_cookie_");
    oCP["name"] = sCookieName.append(m_sRegisteredAs);
    oCP["value"] = sCopy;
    response->SetCookie(oCP);

    // more attributes can go here

    return HTTPRESPONSECODE_200_OK;
}

int main(int argc, char **argv)
{

    cout << getEHSconfig() << endl;
    if (argc < 4) {
        string cmd = basename(argv[0]);
        cerr << "Usage: " << cmd << " [mode] [port] [file] <delay> <threadcount> <norouterequest>)" << endl;
        cerr << "\tModes: 1 - Single Threaded (last parameter ignored)" << endl;
        cerr << "\tModes: 2 - Multithreaded, fixed number of threads" << endl;
        cerr << "\tModes: 3 - Multithreaded, one thread per request (last parameter ignored)" << endl;
        cerr << "\tnorouterequest: if anything is specified, requests will not be routed" << endl;
        return 0;
    }

    int nDelay = 0;
    int nThreadCount = 1;
    int nMode = atoi(argv[1]);

    if (argc >= 5) {
        nDelay = atoi(argv[4]);
    }
    if (argc >= 6) {
        nThreadCount = atoi(argv[5]);
    }

    EHSServerParameters oSP;
    oSP["port"] = argv[2];
    if (argc >= 7) {
        oSP["norouterequest"] = 1;
    }
    switch (nMode) {
        case 1:
            cout << "Running in single threaded mode" << endl;
            oSP["mode"] = "singlethreaded";
            break;
        case 2:
            cout << "Running with a thread pool of " << nThreadCount << " threads" << endl;
            oSP["mode"] = "threadpool";
            oSP["threadcount"] = nThreadCount;
            break;
        case 3:
            cout << "Running with one thread per request" << endl;
            oSP["mode"] = "onethreadperrequest";
            break;
        default:
            cerr << "Invalid mode specified: must be 1, 2, or 3" << endl;
            return 0;
    }
    cout << "binding to " << argv[2] << endl;
    cout << "Delay set to " << nDelay << " seconds" << endl;

    tester srv(argv[3], nDelay);
    try {
        srv.StartServer(oSP);

        tester a(argv[3]);
        // Handles URIs like http://localhost/a
        srv.RegisterEHS(&a, "a");

        tester b(argv[3]);
        // Handles URIs like http://localhost/b
        srv.RegisterEHS(&b, "b");

        tester aa(argv[3]);
        // Handles URIs like http://localhost/a/a
        a.RegisterEHS(&aa, "a");

        tester ab(argv[3]);
        // Handles URIs like http://localhost/a/b
        a.RegisterEHS(&ab, "b");


        // if in single threaded mode,
        // we must handle data explicitly.
        kbdio kbd;
        cout << "Press q to terminate ..." << endl;
        while (!(srv.ShouldTerminate() || kbd.qpressed())) {
            if (1 == nMode) {
                srv.HandleData(1000); // waits for 1 second
            } else {
                usleep(300000);
            }
        }
        srv.StopServer();
    } catch (exception &e) {
        cerr << "ERROR: " << e.what() << endl;
    }
    return 0;
}