This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/MSP432E401Y: NDK HTTPServer cookie handling -> passing cookies to URLhandler

Part Number: MSP432E401Y
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Hi all,

I have the same problem of cookies handling as described in this thread and I have written a small extension to httpserver.c from the NDK to handle the cookies header. (see below)

Identifying the cookies works but now I am not sure how to pass the cookies string to the URL handler in my project (I am using urlsimple.c).

One idea is to extend the process handler, but I am not sure if this is a good idea:

int URLSimple_process(URLHandler_Handle urlHandler, int method,
                      const char * url, const char * urlArgs,
                      int contentLength, int ssock, char * cookies)

Any ideas / help is greatly appreciated.

Best regards,
Christian

P.S.
It is a bit annoying that the NDK is not natively supporting cookies. Is there some plan to do this in the future?

My changes to httpserver.c:

// Cookie-fix
// Added additional tag id 6 for cookies
#define TAG_COOKIE      6
#define TAG_CLEN        7
#define TAG_AUTH        8
#define TAG_HOST        9
#define TAG_DONTCARE    10
#define TAG_LASTMETHOD  TAG_COOKIE
// Cookie-fix

static int httpExtractTag(char * tag)
{

    static int x = 1;
    x++;

    if (!strncmp("GET", tag, 3)) {
        return (TAG_GET) ;
    }
    if (!strncmp("PUT", tag, 3)) {
        return (TAG_PUT);
    }
    if (!strncmp("PATCH", tag, 5)) {
        return (TAG_PATCH);
    }
    if (!strncmp("DELETE", tag, 6)) {
        return (TAG_DELETE);
    }
    if (!strncmp("POST", tag, 4)) {
        return (TAG_POST);
    }
    if (!strncmp("Content-Length: ", tag, 16)) {
        return (TAG_CLEN);
    }
    if (!strncmp("Host: ", tag, 6)) {
        return (TAG_HOST);
    }
    // Cookie-fix
    if (!strncmp("Cookie: ", tag, 8)) {
        return (TAG_COOKIE);
    }
    // Cookie-fix

    return (TAG_DONTCARE);
}

  • We still do not have cookie support in the NDK.

  • Okay,

    I wrote a little extension to cover handover of contentType and cookies. Here is the documentation, maybe this helps others, too.

    The project is based on "httpserver_MSP_EXP432E401Y_tirtos_ccs_syscfg".

    I copied these files to the project:

    • httpserver.c
    • httpserver.h
    • urlhandler.h

    I will post the modified files as additional replies...

  • httpserver.c:

    /*
     * Copyright (c) 2012-2018 Texas Instruments Incorporated - http://www.ti.com
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */

    #if defined(xdc_runtime_Log_DISABLE_ALL) && \
        defined(xdc_runtime_Assert_DISABLE_ALL)
    #define NOREGISTRY 1
    #endif

    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h>
    #include <stdio.h>
    #include <errno.h>

    /*
     * This shouldn't be Linux-specific; every environment should #include
     * <unistd.h> for the definition of close().
     *
     * Unfortunately, until NS socket descriptors are _file_ descriptors,
     * we have a conflict between the NS-defined close() (for sockets) and
     * the unistd.h-defined close() (for files).
     *
     * Linux doesn't have this conflict, so it (correctly) uses
     * unistd.h-defined close().  Everyone else uses NS-defined close(),
     * so they should _not_ bring in unistd.h>.
     */
    #ifdef __linux__
    #include <unistd.h>
    #endif

    #include <sys/socket.h>
    #include <sys/select.h>

    #ifdef __linux__
    #include <fcntl.h>
    #include <sys/eventfd.h>
    #endif

    #ifdef __NDK__
    #include <ti/sysbios/knl/Task.h>
    #endif

    #include <netinet/in.h>
    #include <arpa/inet.h>

    // Cookie-ctype-ext
    // Fix: Includes pointing to NTAG from project-based httpserver.c
    #include "urlhandler.h"
    //#include "ti/net/http/urlhandler.h"
    //#include "logging.h"
    #include "ti/net/http/logging.h"

    #include "httpserver.h"
    //#include "http.h"
    #include "ti/net/http/http.h"
    // Cookie-ctype-ext


    #include <pthread.h>
    #include <mqueue.h>

    #define TAG_GET         1
    #define TAG_POST        2
    #define TAG_PUT         3
    #define TAG_PATCH       4
    #define TAG_DELETE      5

    // Cookie-ctype-ext
    // Added additional tag id 6 for cookies
    //#define TAG_LASTMETHOD  TAG_DELETE
    //#define TAG_CLEN        6
    //#define TAG_AUTH        7
    //#define TAG_HOST        8
    //#define TAG_DONTCARE    9
    #define TAG_CTYPE       6
    #define TAG_COOKIE      7
    #define TAG_CLEN        8
    #define TAG_AUTH        9
    #define TAG_HOST        10
    #define TAG_DONTCARE    11
    #define TAG_LASTMETHOD  TAG_COOKIE
    // Cookie-ctype-ext


     /* end of line - line content in buf */
    #define EOLINE  1

    /* end of header */
    #define EOHEADER 0

    /* unknown error */
    #define SOCKETERROR -1

    #define TIMEOUTUS  (500 * 1000) /* 500 ms */

    /* HomeKit requires disconnecting rudely, so set this to 1 */
    #define HTTPSRV_DISCONNECTRUDE 1

    /* TODO - Needs to be configurable by the user */
    #define SERVESENDTHREAD_STACKSIZE (2560)

    #define MQ_MAXMSG  3
    #define MQ_MSGSIZE 1

    #define LOOPBACKADDR    0x7F000001 /* 127.0.0.1 */

    #define DEFAULT_TIMEOUT 60
    #define DEFAULT_MAXLINELEN 256
    #define DEFAULT_MAXURILEN 112
    #define DEFAULT_MAXSESSIONS 16

    typedef struct Session {
        struct Session * next;
        int s;
        char * line;
        char * uri;
        bool stop;
        int sendRequest;
        HTTPServer_Handle srv;
        URLHandler_Handle urlh[];
    } Session;

    typedef struct HTTPServer_Object {
        int skt;
    #ifdef __linux__
        int cmdfd;                  /* command pipe */
    #else
        uint16_t port;
        bool isPortSet;
    #endif
        int timeout;
        int maxLineLen;
        int maxURILen;
        int maxSessions;
        int numURLh;
        bool stop;
        bool isSecure;
        pthread_mutex_t sendMutex;
        mqd_t sendMq;
        Session * sessions;
        SlNetSockSecAttrib_t * secAttribs;
        URLHandler_Setup setup[];
    } HTTPServer_Object;

    typedef struct SendThreadArgs {
        HTTPServer_Handle srv;
        char *mqName;
    } SendThreadArgs;

    enum SendType {
        EVENT_NOTIFY = 'E',
        HTTP2_PING = 'P',
        STOP_THREAD = 'S'
    };

    #ifndef NOREGISTRY
    Registry_Desc ti_net_http_HTTPServer_desc;
    #endif

    #define POLLPERIOD 50

    static void inline closeSocket(int s)
    {
        Log_print1(Diags_ENTRY, "closeSocket> enter (%d)", s);

        close(s);

        Log_print0(Diags_EXIT, "closeSocket> exit");
    }

    static int httpExtractTag(char * tag)
    {

        static int x = 1;
        x++;

        if (!strncmp("GET", tag, 3)) {
            return (TAG_GET) ;
        }
        if (!strncmp("PUT", tag, 3)) {
            return (TAG_PUT);
        }
        if (!strncmp("PATCH", tag, 5)) {
            return (TAG_PATCH);
        }
        if (!strncmp("DELETE", tag, 6)) {
            return (TAG_DELETE);
        }
        if (!strncmp("POST", tag, 4)) {
            return (TAG_POST);
        }
        if (!strncmp("Content-Length: ", tag, 16)) {
            return (TAG_CLEN);
        }
        if (!strncmp("Host: ", tag, 6)) {
            return (TAG_HOST);
        }
        // Cookie-ctype-ext
        if (!strncmp("Content-Type: ", tag, 14)) {
            return (TAG_CTYPE);
        }
        if (!strncmp("Cookie: ", tag, 8)) {
            return (TAG_COOKIE);
        }
        // Cookie-ctype-ext

        return (TAG_DONTCARE);
    }

    static int handle404(int s, int contentLength)
    {
        int len;
        uint8_t buf[32];

        /* dump the request body */
        while (contentLength > 0) {
            len = contentLength > sizeof(buf) ? sizeof(buf) : contentLength;
            len = recv(s, buf, len, 0);
            if (len > 0) {
                contentLength -= len;
            }
            else {
                break;
            }
        }

        HTTPServer_sendErrorResponse(s, HTTP_SC_NOT_FOUND);

        return (contentLength);
    }

    static int httpRecvLine(int s, char * buf, int bufLen)
    {
        ssize_t nbytes;
        int len;

        if ((nbytes = recv(s, buf, 2, 0)) <= 0) {
            if (nbytes < 0) {
                HTTPServer_sendErrorResponse(s, HTTP_SC_BAD_REQUEST);
            }

            return SOCKETERROR;
        }

        if (buf[0] == '\r' && buf[1] == '\n') {
            return EOHEADER;
        }

        len = 2;
        do {
            if ((nbytes = recv(s, &buf[len], 1, 0)) <= 0) {
                if (nbytes < 0) {
                    HTTPServer_sendErrorResponse(s, HTTP_SC_BAD_REQUEST);
                }

                return SOCKETERROR;
            }

            if (++len == bufLen) {
                HTTPServer_sendErrorResponse(s, HTTP_SC_REQUEST_ENTITY_TOO_LARGE);

                return SOCKETERROR;
            }
        } while (!(buf[len - 2] == '\r' && buf[len - 1] == '\n'));

        buf[len] = 0;

        return EOLINE;
    }

    static int transact(HTTPServer_Handle srv, Session * session)
    {
        int s = session->s;
        char * line = session->line;
        int lineLen = srv->maxLineLen;
        char * uri = session->uri;
        int uriLen = srv->maxURILen;
        char * uriArgs;
        int method;
        int status;
        int contentLength;
        char * beg = NULL;
        char * end = NULL;
        int i;

        // Cookie-ctype-ext
    #define COOKIES_BUF_SIZE 256
        char cookies[COOKIES_BUF_SIZE];
    #define CTYPE_BUF_SIZE 128
        char contentType[CTYPE_BUF_SIZE];
        // Cookie-ctype-ext

        if ((status = httpRecvLine(s, line, lineLen)) <= 0) {
            Log_print1(Diags_ANALYSIS, "transact> httpRecvLine %d", (IArg)status);
            status = 1;
            goto END;
        }

        /*
         *  Parse the request line which should look like:
         *
         *  METHOD /uri HTTP/1.1
         *
         * TODO: handle cases of missing URI and or HTTP/1.1
         * TODO: look for orphan CR or LF in line
         */
        if ((method = httpExtractTag(line)) > TAG_LASTMETHOD) {
            HTTPServer_sendErrorResponse(s, HTTP_SC_BAD_REQUEST);
            status = 1;
            goto END;
        }

        beg = strchr(line, ' ');
        if (beg == NULL) {
            /* missing the URI */
            HTTPServer_sendErrorResponse(s, HTTP_SC_BAD_REQUEST);
            status = 1;
            goto END;
        }

        while (*beg == ' ') {
            beg++;
        }

        end = strchr(beg, ' ');
        if (end == NULL) {
            /* missing HTTP/1.x */
            HTTPServer_sendErrorResponse(s, HTTP_SC_BAD_REQUEST);
            status = 1;
            goto END;
        }

        if (uriLen > (end - beg)) {
            strncpy(uri, beg, end - beg);
            uri[end - beg] = 0;
        }
        else {
            HTTPServer_sendErrorResponse(s, HTTP_SC_REQUEST_ENTITY_TOO_LARGE);
            status = 1;
            goto END;
        }

        /* extract any CGI args from the URI */
        if ((uriArgs = strchr(uri, '?'))) {
            *uriArgs++ = 0;
        }

        /*
         *  Receive and process all the remaining fields in the
         *  request header, looking for the ones we care about.
         *
         *  TODO: enable users to specify required fields and
         *  get the associated data, possibly via callbacks. Some
         *  of the fields should really go to the URLHandlers,
         *  like Content-Type.
         */

        contentLength = 0;
        while ((status = httpRecvLine(s, line, lineLen)) > 0) {
            int nTag;

            nTag = httpExtractTag(line);

            if (nTag == TAG_CLEN) {
                /* 16 == sizeof("Content-Length: ") */
                contentLength = atoi(line + 16);
            }

            // Cookie-ctype-ext
            if (nTag == TAG_CTYPE) {
                if (strlen(line) > 14) { /* 14 == sizeof("Content-Type: ") */
                    strncpy(contentType, &line[14], CTYPE_BUF_SIZE);
                    cookies[CTYPE_BUF_SIZE-1] = 0;
                }
            }
            if (nTag == TAG_COOKIE) {
                if (strlen(line) > 8) { /* 8 == sizeof("Cookie: ") */
                    strncpy(cookies, &line[8], COOKIES_BUF_SIZE);
                    cookies[COOKIES_BUF_SIZE-1] = 0;
                }
            }
            // Cookie-ctype-ext

            for (i = 0; i < srv->numURLh; i++) {
                if (srv->setup[i].scanField) {
                    srv->setup[i].scanField(session->urlh[i], method, uri, line);
                }
            }
        }

        if (status < 0) {
            status = 1;
            goto END;
        }

        Log_print4(Diags_ANALYSIS, "start handler> %p %d %s %d", (IArg)srv, method,
                   (IArg)uri, contentLength);

        status = URLHandler_ENOTHANDLED;
        for (i = 0; i < srv->numURLh; i++) {
            Log_print1(Diags_ANALYSIS, "urlh: %p", (xdc_IArg)session->urlh[i]);
            status = srv->setup[i].process(session->urlh[i], method, uri, uriArgs,
                                           contentType, contentLength, cookies, s);
            if (status != URLHandler_ENOTHANDLED) {
                break;
            }
        }

        if (status == URLHandler_EHANDLEDSTOP) {
            srv->stop = true;
        }

        Log_print2(Diags_ANALYSIS, "finish handler> %p %d", (IArg)srv, status);

        if (status == URLHandler_ENOTHANDLED) {
            status = handle404(s, contentLength);
        }
        else if (status == URLHandler_EERRORHANDLED) {
            status = 1;
        }
        else {
            status = 0;
        }

    END:
        return (status);
    }

    static void deleteSession(HTTPServer_Handle srv, Session * session)
    {
        int i;

        Log_print2(Diags_ENTRY, "deleteSession> enter (%p, %p)",
                (IArg)srv, (IArg)session);

        if (session) {
            for (i = 0; i < srv->numURLh; i++) {
                if (session->urlh[i]) {
                    srv->setup[i].del(&session->urlh[i]);
                }
            }
            if (session->line) {
                free(session->line);
            }
            if (session->s) {
                closeSocket(session->s);
            }

            free(session);
        }
        Log_print0(Diags_EXIT, "deleteSession> exit");
    }

    static Session * createSession(HTTPServer_Handle srv, int s)
    {
        Session * session;
        int i;
        struct timeval to;

        if ((session = calloc(1, sizeof(Session) +
                              srv->numURLh * sizeof(URLHandler_Handle))) == NULL) {
            return (NULL);
        }

        if ((session->line = malloc(srv->maxLineLen + srv->maxURILen)) == NULL) {
            deleteSession(srv, session);
            return (NULL);
        }

        session->uri = session->line + srv->maxLineLen;
        session->s = s;
        session->stop = false;
        session->next = NULL;
        session->srv = srv;

        for (i = 0; i < srv->numURLh; i++) {
            if (srv->setup[i].create) {
                if ((session->urlh[i] =
                     srv->setup[i].create(srv->setup[i].params,
                                          (URLHandler_Session)session)) == NULL) {

                    deleteSession(srv, session);
                    return (NULL);
                }
            }
            else {
                session->urlh[i] = NULL;
            }
        }

    #if 0 /* TODO - should this be linux-only? or should slnetsock support this? */
    #ifndef __SL__
        struct linger  lgr;

        lgr.l_onoff  = 1;
        lgr.l_linger = 5;
        (void)setsockopt(s, SOL_SOCKET, SO_LINGER, &lgr, sizeof(lgr));

        /* Configure our socket timeout to be 10 seconds */
        to.tv_sec  = 10;
        to.tv_usec = 0;
        (void)setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
    #endif
    #endif
        to.tv_sec  = srv->timeout;
        to.tv_usec = 0;
        (void)setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));

        return (session);
    }

    static void pruneSession(HTTPServer_Handle srv)
    {
        Session * session;
        Session * prev;
        bool found;

        Log_print1(Diags_ENTRY, "pruneSession> enter (%p)", (IArg)srv);

        do {
            prev = NULL;
            found = false;
            for (session = srv->sessions; session; session = session->next) {
                if (session->stop) {
                    if (prev) {
                        prev->next = session->next;
                    }
                    else {
                        srv->sessions = session->next;
                    }
                    found = true;
                    deleteSession(srv, session);
                    break;
                }
                prev = session;
            }
        } while (found);

        Log_print0(Diags_EXIT, "pruneSession> exit");
    }

    static void removeSession(HTTPServer_Handle srv, Session * session)
    {
        session->stop = true;
    }

    static int numSessions(HTTPServer_Handle srv)
    {
        Session * session;
        int num = 0;

        for (session = srv->sessions; session; session = session->next) {
            num++;
        }

        return (num);
    }

    static Session * addSession(HTTPServer_Handle srv, int s)
    {
        Session * newSession;
        Session * session;

        /*
         * If adding this session will make us exceed the max number of supported
         * sessions, remove the first session in the list to make room for this
         * one.
         */
        if (numSessions(srv) >= srv->maxSessions) {
            removeSession(srv, srv->sessions);
        }

        pruneSession(srv);

        if ((newSession = createSession(srv, s))) {
            if (srv->sessions == NULL) {
                srv->sessions = newSession;
            }
            else {
                for (session = srv->sessions; session->next;
                     session = session->next) {
                }
                session->next = newSession;
            }
        }

        Log_print1(Diags_ANALYSIS, "addSession> %d", (IArg)newSession);

        return (newSession);
    }

    void HTTPServer_init(void)
    {
    #ifndef NOREGISTRY
        static int regInit = false;

        if (!regInit) {
            Registry_addModule(&ti_net_http_HTTPServer_desc, "ti.net.http.HTTPServer");
            regInit = true;
        }
    #endif
    }

    void HTTPServer_exit(void)
    {
        /* TODO: can you remove a Registry entry? */
    }

    void HTTPServer_Params_init(HTTPServer_Params *params)
    {
        params->timeout = DEFAULT_TIMEOUT;
        params->maxLineLen = DEFAULT_MAXLINELEN;
        params->maxURILen = DEFAULT_MAXURILEN;
        params->maxSessions = DEFAULT_MAXSESSIONS;
    }

    void HTTPServer_enableSecurity(HTTPServer_Handle srv,
                            SlNetSockSecAttrib_t * securityAttributes,
                            bool beginSecurely)
    {
        srv->secAttribs = securityAttributes;
        srv->isSecure = beginSecurely;
    }

    HTTPServer_Handle HTTPServer_create(const URLHandler_Setup * setup, int numURLh,
                                  HTTPServer_Params * params)
    {
        HTTPServer_Handle srv;

        Log_print3(Diags_ENTRY, "HTTPServer_create> enter (%p), %d, (%p)",
                (IArg)setup, numURLh, (IArg)params);

        if ((srv = malloc(sizeof(HTTPServer_Object) +
                          numURLh * sizeof(URLHandler_Setup)))) {
            int i;

            srv->numURLh = numURLh;
            for (i = 0; i < numURLh; i++) {
                srv->setup[i] = setup[i];
            }

            if (params) {
                srv->timeout = params->timeout;
                srv->maxLineLen = params->maxLineLen;
                srv->maxURILen = params->maxURILen;
                srv->maxSessions = params->maxSessions;
            }
            else {
                srv->timeout = DEFAULT_TIMEOUT;
                srv->maxLineLen = DEFAULT_MAXLINELEN;
                srv->maxURILen = DEFAULT_MAXURILEN;
                srv->maxSessions = DEFAULT_MAXSESSIONS;
            }

            srv->stop = false;
            srv->isSecure = false;
            srv->sessions = NULL;
            srv->sendMq = (mqd_t) -1;
            srv->skt = -1;
            srv->secAttribs = NULL;
    #ifdef __linux__
            srv->cmdfd = eventfd(0, 0);
    #else
            srv->isPortSet = false;
    #endif

    #ifdef __NDK__
            fdOpenSession(Task_self());
    #endif
        }

        Log_print1(Diags_EXIT, "HTTPServer_create> exit (%p)", (IArg)srv);
        return (srv);
    }

    void HTTPServer_delete(HTTPServer_Handle * srv)
    {
        Session * session;
        Session * nextSession;

    #ifdef __NDK__
        fdCloseSession(Task_self());
    #endif

        if (srv && *srv) {
    #ifdef __linux__
            close((*srv)->cmdfd);
    #endif

            for (session = (*srv)->sessions; session; session = nextSession) {
                nextSession = session->next;
                deleteSession(*srv, session);
            }

            free(*srv);
            *srv = NULL;
        }
    }

    static void *serveSendThread(void *p)
    {
        SendThreadArgs *args = p;
        HTTPServer_Handle srv = args->srv;
        char *mqName = args->mqName;
        Session *session;
        mqd_t recvMq;
        char data;

        Log_print1(Diags_ENTRY, "serveSendThread> enter (%p)", (IArg)p);

        recvMq = mq_open(mqName, O_RDONLY);
        if (recvMq == (mqd_t) -1) {
            Log_error1("serveSendThread> couldn't open recv MQ handle, errno %d",
                    errno);
            return (NULL);
        }

        while (1)  {
            if (mq_receive(recvMq, (char *)&data, sizeof(data), NULL) == -1) {
                Log_error1("serveSendThread> failed to recv on MQ, errno %d",
                        errno);
                goto stopThread;
            }

            switch (data) {
                case EVENT_NOTIFY:
                    Log_print0(Diags_ANALYSIS,
                            "serveSendThread> processing event notifications");

                    if (pthread_mutex_lock(&(srv->sendMutex)) != 0) {
                        Log_error0("serveSendThread> failed to acquire lock");
                        goto stopThread;
                    }

                    for (session = srv->sessions; session;
                            session = session->next) {
                        if (session->sendRequest) {
    /*
                            int i;
                            for (i = 0; i < srv->numURLh; i++) {
                                if (srv->setup[i].send) {
                                    srv->setup[i].send(session->urlh[i],
                                            session->s);
                                }
                            }
    */
                            session->sendRequest--;
                        }
                    }

                    if (pthread_mutex_unlock(&(srv->sendMutex)) != 0) {
                        Log_error0("serveSendThread> failed to release lock");
                        goto stopThread;
                    }

                    break;

                case STOP_THREAD:
                    Log_print0(Diags_ANALYSIS, "serveSendThread> stop thread");
                    goto stopThread;

                default:
                    break;
            }
        }

    stopThread:
        mq_close(recvMq);

        return (NULL);
    }

    int HTTPServer_serveSelect(HTTPServer_Handle srv, const struct sockaddr * addr,
                            int len, int backlog)
    {
        int sc;
        Session * session;
        int status;
        fd_set fds;
        int maxs;
        bool prune = false;
        char mqName[16] = {0};
        struct mq_attr mqAttrs;
        pthread_t thread;
        pthread_attr_t attr;
        SendThreadArgs args;
        char data;

        Log_print4(Diags_ENTRY, "HTTPServer_serveSelect> enter (%p), (%p), %d, %d",
                (IArg)srv, (IArg)addr, len, backlog);

    #ifdef __linux__
        snprintf(mqName, sizeof(mqName), "/hk%x", (unsigned int)getpid());
    #else
        snprintf(mqName, sizeof(mqName), "/hk%x", (unsigned int)srv);
    #endif

        if (pthread_mutex_init(&(srv->sendMutex), NULL) != 0) {
            Log_error0("serveSelect> failed to create mutex");

            return (HTTPServer_EMEMFAIL);
        }

        /* Open the reply message queue */
        mqAttrs.mq_flags = 0;
        mqAttrs.mq_curmsgs = 0;
        mqAttrs.mq_maxmsg = MQ_MAXMSG;
        mqAttrs.mq_msgsize = MQ_MSGSIZE;

    #ifdef __linux__
        /* Check if older undeleted MQ exists (can happen in Linux) */
        mq_unlink(mqName);
    #endif
        srv->sendMq = mq_open(mqName, O_CREAT | O_WRONLY, (mode_t) 0644, &mqAttrs);
        if (srv->sendMq == (mqd_t) -1) {
            Log_error1("serveSelect> couldn't open send MQ, errno %d", errno);
            status = HTTPServer_EMQFAIL;
            goto selectFail;
        }

        pthread_attr_init(&attr);
        pthread_attr_setstacksize(&attr, SERVESENDTHREAD_STACKSIZE);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        args.srv = srv;
        args.mqName = mqName;
        if (pthread_create(&thread, &attr, serveSendThread, (void *)&args) != 0) {
            Log_error0("serveSelect> failed to create serveSend thread");
            pthread_attr_destroy(&attr);
            status = HTTPServer_EMEMFAIL;
            goto selectFail;
        }
        pthread_attr_destroy(&attr);

        if ((srv->skt = socket(addr->sa_family, SOCK_STREAM, 0)) == -1) {
            status = HTTPServer_ESOCKETFAIL;
            goto selectFail;
        }

    #ifdef __linux__
        int opt = 1;
        setsockopt(srv->skt, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    #else
        srv->port = ((struct sockaddr_in *)addr)->sin_port;
        srv->isPortSet = true;
    #endif

        if ((srv->secAttribs != NULL) && (srv->isSecure)) {
            status = SlNetSock_startSec(srv->skt, srv->secAttribs,
                                        SLNETSOCK_SEC_BIND_CONTEXT_ONLY |
                                        SLNETSOCK_SEC_IS_SERVER);
            if (status < 0) {
                goto selectFail;
            }
        }

        if ((status = bind(srv->skt, addr, len)) == -1) {
            status = HTTPServer_EBINDFAIL;
            goto selectFail;
        }

        if ((status = listen(srv->skt, backlog)) == -1) {
            status = HTTPServer_ELISTENFAIL;
            goto selectFail;
        }

        status = 0;
        while (1) {
            int result;

            FD_ZERO(&fds);
            FD_SET(srv->skt, &fds);
            maxs = srv->skt;
            prune = false;

    #ifdef __linux__
            /* add command pipe file descriptor */
            FD_SET(srv->cmdfd, &fds);
            maxs = (srv->cmdfd > maxs ? srv->cmdfd : maxs);
    #endif

            for (session = srv->sessions; session; session = session->next) {
                if (session->stop) {
                    prune = true;
                }
                else {
                    FD_SET(session->s, &fds);
                    if (session->s > maxs) {
                        maxs = session->s;
                    }
                }
            }

            /* TODO: add timeout support to close dormant clients */
            result = select(maxs + 1, &fds, NULL, NULL, NULL);

    #ifdef __linux__
            /* check command pipe for data */
            if (FD_ISSET(srv->cmdfd, &fds)) {
                uint64_t event;
                read(srv->cmdfd, &event, sizeof(event)); /* just clear for now */
            }
    #endif

            if (srv->stop || result < 0) {
                for (session = srv->sessions; session; session = session->next) {
                    removeSession(srv, session);
                }
                pruneSession(srv);
                status = srv->stop ? 0 : -1;
                srv->stop = false;
                break;
            }

            if (FD_ISSET(srv->skt, &fds)) {
                sc = accept(srv->skt, NULL, NULL);
                if (sc == -1) {
                    if (errno == ENFILE) {
                        Log_error0("Too many connections open, no sockets are "
                                "available to receive new connection.");
                    }
                    else {
                        status = HTTPServer_EACCEPTFAIL;
                        break;
                    }
                }
                else {
                    addSession(srv, sc);

                    if ((srv->secAttribs != NULL) && (srv->isSecure)) {
                        /* Start the tls session between server and new client*/
                        status = SlNetSock_startSec(sc, srv->secAttribs,
                                    SLNETSOCK_SEC_START_SECURITY_SESSION_ONLY);
                        if (status < 0) {
                            goto selectFail;
                        }
                    }

                }
            }

            if (pthread_mutex_lock(&(srv->sendMutex)) != 0) {
                status = HTTPServer_EMUTEXFAIL;
                break;
            }

            for (session = srv->sessions; session; session = session->next) {
                if (FD_ISSET(session->s, &fds)) {
                    if (transact(srv, session)) {
                        Log_print1(Diags_ANALYSIS, "closing %p", session->s);
                        removeSession(srv, session);
                        prune = true;
                    }
                }
            }

            if (pthread_mutex_unlock(&(srv->sendMutex)) != 0) {
                status = HTTPServer_EMUTEXFAIL;
                break;
            }

            if (srv->stop) {
                for (session = srv->sessions; session; session = session->next) {
                    removeSession(srv, session);
                }
                pruneSession(srv);
                status = 0;
                srv->stop = false;
                break;
            }

            /* Check if any sessions has stopped if we haven't already */
            if (!prune) {
                for (session = srv->sessions; session; session = session->next) {
                    if (session->stop) {
                        prune = true;
                        break;
                    }
                }
            }

            if (prune) {
                pruneSession(srv);
            }
        }

    selectFail:
        pthread_mutex_destroy(&(srv->sendMutex));

        if (status != HTTPServer_EMQFAIL) {
    #ifndef __linux__
            srv->isPortSet = false;
    #endif
            /* stop serveSendThread */
            data = STOP_THREAD;
            mq_send(srv->sendMq, &data, sizeof(data), 0);
            pthread_join(thread, NULL);

            /* clean up */
            mq_close(srv->sendMq);
            mq_unlink(mqName);

            if (srv->skt != -1) {
                closeSocket(srv->skt);
                srv->skt = -1;
            }
        }

        Log_print1(Diags_EXIT, "HTTPServer_serveSelect> exit (%d)", status);
        return (status);
    }

    int HTTPServer_processClient(HTTPServer_Handle srv, int sock)
    {
        Session * session;
        int status = 0;

        Log_print2(Diags_ENTRY, "_processClient> enter (srv:%p, sock:%d)",
               (IArg)srv, (IArg)sock);

        session = createSession(srv, sock);
        if (session == NULL) {
            Log_error0("Failed to create session");
            status = -1;
            goto exit;
        }

        Log_print1(Diags_ANALYSIS, "processClient> start %p", (IArg)srv);

        while (transact(srv, session) == 0) {
        }

        Log_print1(Diags_ANALYSIS, "finish processClient> %p", (IArg)srv);

        deleteSession(srv, session);

    exit:
        Log_print0(Diags_EXIT, "_processClient> exit");

        return (status);
    }

    bool HTTPServer_stop(HTTPServer_Handle srv, uint32_t timeout)
    {
        srv->stop = true;
    #ifndef __linux__
        int skt = -1;
        struct sockaddr_in inaddr;
        char buf[] = "stop";
    #endif

        /* Wake up select */
    #ifdef __linux__
        {
        uint64_t event = 1;
        write(srv->cmdfd, &event, sizeof(event));
        }
    #else
        if (!srv->isPortSet) {
            goto stop_error;
        }
        inaddr.sin_family = AF_INET;
        inaddr.sin_port = srv->port;
        inaddr.sin_addr.s_addr = htonl(LOOPBACKADDR);
        if ((skt = socket(inaddr.sin_family, SOCK_STREAM, 0)) == -1) {
            goto stop_error;
        }

        if (connect(skt, (struct sockaddr *)&inaddr, sizeof(inaddr)) == -1) {
            goto stop_error;
        }

        send(skt, buf, sizeof(buf), 0);
    #endif

        while (srv->stop && timeout > POLLPERIOD) {
            _HTTPServer_sleepms(POLLPERIOD);
            timeout -= POLLPERIOD;
        }

    #ifndef __linux__
    stop_error:
        if (skt != -1) {
            closeSocket(skt);
        }
    #endif

        return (!srv->stop);
    }

    void HTTPServer_requestSend(URLHandler_Session urls)
    {
        Session * session = (Session *)urls;
        char data = EVENT_NOTIFY;

        session->sendRequest++;

        if (session->srv->sendMq != (mqd_t) -1) {
            if (mq_send(session->srv->sendMq, &data, sizeof(data), 0) == -1) {
                Log_error0("HTTPServer_requestSend> serveSendThread signal failed");
            }
            else {
                Log_print0(Diags_ANALYSIS,
                        "HTTPServer_requestSend> signaled serveSendThread");
            }
        }
    }

    void HTTPServer_stopSession(URLHandler_Session urls)
    {
        Log_print1(Diags_ENTRY, "HTTPServer_stopSession> enter (%p)", (IArg)urls);

        Session * session = (Session *)urls;
        session->stop = true;

        Log_print0(Diags_EXIT, "HTTPServer_stopSession> exit");
    }

    bool HTTPServer_isSessionSecure(URLHandler_Session sess)
    {
        Session * session = (Session *)sess;

        return session->srv->isSecure;
    }

  • urlhandler.h:

    /*
     * Copyright (c) 2014-2018, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */

    /*
     * ======== ti/net/http/urlhandler.h ========
     */
    /**
     *  @file  ti/net/http/urlhandler.h
     *
     *  @brief URL Handler interface
     */
    /**
     *  @addtogroup ti_net_http_HTTPServer HTTP Server
     *
     */

    #ifndef ti_net_http__URLHandler__include
    #define ti_net_http__URLHandler__include

    /*! @ingroup ti_net_http_HTTPServer */
    /*@{*/

    #include <stddef.h>

    #ifdef __cplusplus
    extern "C" {
    #endif

    #define URLHandler_GET 1
    #define URLHandler_POST 2
    #define URLHandler_PUT 3
    #define URLHandler_PATCH 4
    #define URLHandler_DELETE 5

    #define URLHandler_ENOTHANDLED 0
    #define URLHandler_EHANDLED 1
    #define URLHandler_EERRORHANDLED 2
    #define URLHandler_EHANDLEDSTOP 3

    /**
     *  @brief A placeholder used to refer to a user-defined type.
     *
     *  This object handle is the type returned from the
     *  URLHandler_CreateFxn and passed to all other URLHandler_*
     *  functions.
     *
     */
    typedef struct URLHandler_Object * URLHandler_Handle;
    typedef struct URLHandler_State * URLHandler_Session;

    /**
     *  @brief Create a user-defined URLHandler_Object
     *
     *  This function (if used) should be used to instantiate a
     *  user-defined URLHandler_Handle object that contains whatever
     *  information is deemed necessary to pass to other URLHandler_*
     *  functions while the server is running. The handle of the user-
     *  defined type should be cast as a URLHandler_Handle before returning
     *  it from this function. The handle should be recast as the user-
     *  defined type before accessing it in other URLHandler_* functions.
     *
     *  @param[in]  params  Optional parameters to specify characteristics
     *  @param[in]  session Handler to current client session
     *
     *  @remarks    The @c session argument is not yet used, but may be in the
     *              future
     *
     *  @retval     URLHandler instance handle
     *
     *  @sa URLHandler_DeleteFxn()
     */
    typedef URLHandler_Handle (*URLHandler_CreateFxn)(void * params,
            URLHandler_Session session);

    /**
     *  @brief Process an HTTP request
     *
     *  This method is called once per URL Handler, for every request
     *  received by the server. Its purpose is to fetch the resource
     *  requested and have it sent to the client via HTTPServer_send*
     *  methods.
     *
     *  @param[in]  u               Handle to the URL Handler containing relevant
     *                              data
     *  @param[in]  method          HTTP method of the request being parsed
     *  @param[in]  url             URI of the current request
     *  @param[in]  urlArgs         The query string, if present
     *  @param[in]  contentLength   Content-Length (body length) header value, if
     *                              present
     *  @param[in]  s               TCP/IP socket connected to a client
     *
     *  @retval     int Return status
     *
     *  @sa HTTPServer_sendResponse()
     */

    // Cookie-ctype-ext
    //typedef int (*URLHandler_ProcessFxn)(URLHandler_Handle u, int method,
    //        const char * url, const char * urlArgs, int contentLength, int s);
    // Overwrite definition to allow cookies as string
    typedef int (*URLHandler_ProcessFxn)(URLHandler_Handle u, int method,
            const char * url, const char * urlArgs, char * contentType, int contentLength, char * cookies, int s);
    // Cookie-ctype-ext


    /**
     *  @brief Scan for specific request headers
     *
     *  This function can be used to process headers of incoming requests.
     *  Every URL Handler with this function defined will have each header
     *  passed into this function, one by one. It is called when a request
     *  is received by the server, before the request is sent to the
     *  URLHandler_ProcessFxn.
     *
     *  @param[in]  u       Handle to the URL Handler containing relevant data
     *  @param[in]  method  HTTP method of the request being parsed
     *  @param[in]  url     URI of the current request
     *  @param[in]  field   Specific request line containing the header
     *
     *  @sa URLHandler_ProcessFxn()
     */
    typedef void (*URLHandler_ScanFieldFxn)(URLHandler_Handle u, int method,
            const char * url, const char * field);

    /**
     *  @brief Delete a URLHandler
     *
     *  This function is called when the session associated with the
     *  input handler is closed.
     *
     *  @param[in]  u   The Handler for deletion
     *
     */
    typedef void (*URLHandler_DeleteFxn)(URLHandler_Handle * u);

    /** @cond INTERNAL
     *  @brief Send an event notification from the server
     *
     *  This function can be used to alert clients of events and send
     *  out status updates from the server, possibly based on state data
     *  contained within the given URL Handler. This function is triggered
     *  by HTTPServer_requestSend
     *
     *  @param[in]  u   A handle to the URL Handler containing relevant data
     *  @param[in]  s   TCP/IP socket connected to a client
     *
     */
    typedef void (*URLHandler_SendFxn)(URLHandler_Handle u, int s);
    /** @endcond */

    /**
     *  @brief Structure containing URL Handler components
     *
     *  This structure contains parameters needed for setup of a user-
     *  defined URLHandler object and pointers to associated user-defined
     *  URLHandler_* functions. The created HTTP Server maintains a table
     *  of this data structure for each unique URL Handler.
     *
     */
    typedef struct URLHandler_Setup {
        /**
         *  @brief Parameters needed for URL Handler instantiation
         */
        void * params;

        /**
         *  @brief URL Handler Create function
         */
        URLHandler_CreateFxn create;

        /**
         *  @brief URL Handler Delete function
         */
        URLHandler_DeleteFxn del;

        /**
         *  @brief URL Handler Process function
         */
        URLHandler_ProcessFxn process;

        /**
         *  @brief Scan field function
         */
        URLHandler_ScanFieldFxn scanField;

        /**
         *  @brief This field is reserved - set to NULL
         */
        void * reserved1;
    } URLHandler_Setup;

    /*! @} */
    #ifdef __cplusplus
    }
    #endif

    #endif

  • httpserver.h:

    /*
     * Copyright (c) 2012-2018 Texas Instruments Incorporated - http://www.ti.com
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */

    /*
     * ======== ti/net/http/httpserver.h ========
     */
    /**
     *  @file  ti/net/http/httpserver.h
     *
     *  @brief HTTP Server services
     */
    /**
     *  @addtogroup ti_net_http_HTTPServer HTTP Server
     *
     *  @brief      The HTTP server provides APIs to instantiate an HTTP
     *              server, and handle requests from HTTP clients.
     *
     *  ## Library Usage ##
     *
     *  To use the HTTPServer APIs, the application should include its header file
     *  as follows:
     *  @code
     *  #include <ti/net/http/httpserver.h>
     *  @endcode
     *
     *  And, add the following HTTP library to the link line:
     *  @code
     *  .../source/ti/net/http/{toolchain}/{isa}/httpserver_{profile}.a
     *  @endcode
     *
     *  ============================================================================
     */

    #ifndef ti_net_http_HTTPServer__include
    #define ti_net_http_HTTPServer__include

    /*! @ingroup ti_net_http_HTTPServer */
    /*@{*/

    #include <stdint.h>
    #include <stdbool.h>
    #include <sys/socket.h>
    #include <ti/net/slnetsock.h>

    // Cookie-ctype-ext
    //#include "urlhandler.h"
    #include "ti/net/http/urlhandler.h"
    // Cookie-ctype-ext

    #ifdef __cplusplus
    extern "C" {
    #endif

    /**
     *  @brief Internal accept() call failed
     */
    #define HTTPServer_EACCEPTFAIL   (-2)

    /**
     *  @brief Internal network socket creation failure
     */
    #define HTTPServer_ESOCKETFAIL   (-3)

    /**
     *  @brief Internal bind() call failed
     */
    #define HTTPServer_EBINDFAIL     (-4)

    /**
     *  @brief Internal listen() call failed
     */
    #define HTTPServer_ELISTENFAIL   (-5)

    /**
     *  @brief Internal memory allocation or object creation failure
     */
    #define HTTPServer_EMEMFAIL      (-6)

    /**
     *  @brief Internal mq creation failure
     */
    #define HTTPServer_EMQFAIL       (-7)

    /**
     *  @brief Internal mutex-related failure
     */
    #define HTTPServer_EMUTEXFAIL    (-8)

    /** @cond INTERNAL */
    /* internal utility fxn, not for end users */
    extern void _HTTPServer_sleepms(uint32_t time);
    /** @endcond */

    /**
     *  @brief HTTPServer instance create parameters
     */
    typedef struct HTTPServer_Params {
        /**
         *  @brief Receive timeout, in seconds
         */
        int timeout;
        /**
         *  @brief Maximum characters in a request header line
         *
         *  @remarks    If a client request includes a header with more
         *              characters than this, the server will send an error
         *              response of HTTP_TOO_BIG.
         */
        int maxLineLen;

        /**
         *  @brief Maximum characters in a URI request
         *
         *  @remarks    If a client requests a URI with more characters than
         *              this, the server will send an error response of
         *              HTTP_TOO_BIG.
         */
        int maxURILen;

        /**
         *  @brief Maximum number of active sessions
         *
         *  @remarks    If a new client arrives and there are currently
         *              @c maxSessions clients connected, the oldest
         *              connection will be dropped to make room for the
         *              new one.
         */
        int maxSessions;
    } HTTPServer_Params;

    /**
     *  @brief HTTPServer instance object handle
     */
    typedef struct HTTPServer_Object * HTTPServer_Handle;

    /**
     *  @brief Initialize the HTTPServer module
     *
     *  @remark     This function is used to initialize the HTTPServer module.
     *              Call this function before calling any other HTTPServer
     *              functions.
     *
     *  @remark     This function must be serialized by the caller.
     */
    extern void HTTPServer_init(void);

    /**
     *  @brief Initialize the instance create params structure
     *
     *  @param[in]  params  params structure to initialize
     */
    extern void HTTPServer_Params_init(HTTPServer_Params *params);

    /**
     *  @brief Attach security params to the created, but not yet initialized server
     *
     *  @param[in]  srv  Pointer to the server that will take on the attributes.
     *  @param[in]  securityAttributes A list of security objects as detailed in
     *                                 slnetsock.h.
     *  @param      beginSecurely Whether to activate security right away or not.
     *                            This is typically set to true.
     *
     *  @remark     The securityAttributes passed to this function must remain
     *              in memory for the duration of the program. They cannot be
     *              safely freed before the server has been deleted.
     *  @remark     Call this function before HTTPServer_serveSelect.
     *              beginSecurely is typically set to true as there is currently
     *              no way to activate security after this function has been called
     *              and returns.
     */
    extern void HTTPServer_enableSecurity(HTTPServer_Handle srv,
            SlNetSockSecAttrib_t * securityAttributes, bool beginSecurely);

    /**
     *  @brief Create an HTTPServer instance
     *
     *  @param[in]  urlh    Array of URLHandler setup descriptors
     *  @param      numURLh Number of elements in the @c urlh array
     *  @param[in]  params  Optional parameters to specify characteristics - use
     *                      NULL for defaults
     *
     *  @httpserver_init_precondition
     *
     *  @retval HTTPServer instance handle
     *  @retval NULL if unable to create the instance
     *
     *  @sa HTTPServer_Params_init()
     *  @sa HTTPServer_delete()
     */
    extern HTTPServer_Handle HTTPServer_create(const URLHandler_Setup * urlh,
            int numURLh, HTTPServer_Params * params);

    /**
     *  @brief Delete an HTTPServer instance
     *
     *  @param[in,out] srv    Pointer containing a handle to the instance to
     *                        delete.
     *
     *  @httpserver_init_precondition
     *
     *  @remarks    Upon successful return, the handle pointed to by @c handlePtr
     *              will be invalid.
     */
    extern void HTTPServer_delete(HTTPServer_Handle * srv);

    /** @cond INTERNAL */
    /**
     *  @brief Process the HTTP transactions for a client socket
     *
     *  @param srv  server instance returned from HTTPServer_create
     *  @param s    TCP/IP socket connected to a client (returned from accept())
     *
     */
    extern int HTTPServer_processClient(HTTPServer_Handle srv, int s);
    /** @endcond */

    /**
     *  @brief Send a simple, complete response to a client
     *
     *  This function is typically called by a URL Handler, in response to
     *  handling a URL request.
     *
     *  @param[in]  s       TCP/IP socket connected to a client
     *  @param[in]  status  Status Code associated with the response
     *  @param[in]  type    Content-type of the response
     *  @param[in]  len     Number of bytes in the response buffer @c buf
     *  @param[in]  buf     Response buffer
     *
     *  @httpserver_init_precondition
     *
     *  @remarks    This function sends 2 response headers, "Content-Length" and
     *              "Content-Type".  To send custom response headers, use
     *              HTTPServer_sendResponse().
     *
     *  @sa HTTPServer_sendErrorResponse()
     *  @sa HTTPServer_sendResponseChunked()
     */
    extern void HTTPServer_sendSimpleResponse(int s, int status,
            const char * type, size_t len, const void * buf);

    /**
     *  @brief Send a complete response to a client
     *
     *  This function is typically called by a URL Handler, in response to
     *  handling a URL request.
     *
     *  @param[in]  s       TCP/IP socket connected to a client
     *  @param[in]  status  Status Code associated with the response
     *  @param[in]  headers Optional response headers
     *  @param[in]  numHeaders  number of elements in @c headers
     *  @param[in]  len     Number of bytes in the response buffer @c buf
     *  @param[in]  buf     Response buffer
     *
     *  @httpserver_init_precondition
     *
     *  @remarks    This function sends the user supplied @c headers as
     *              response headers, followed by a generated
     *              "Content-Length" header (with a value of @c len).  If
     *              you only need to send "Content-Length" and
     *              "Content-Type" headers, consider using
     *              HTTPServer_sendSimpleResponse().
     *
     *  @sa HTTPServer_sendErrorResponse()
     *  @sa HTTPServer_sendResponseChunked()
     */
    extern void HTTPServer_sendResponse(int s, int status,
            const char * headers[], int numHeaders, size_t len, const void * buf);

    /**
     *  @brief Send an error response to a client
     *
     *  This function is typically called by a URL Handler, in response to
     *  handling a URL request.
     *
     *  @param[in]  s       TCP/IP socket connected to a client
     *  @param[in]  status  Status Code associated with the response
     *
     *  @httpserver_init_precondition
     *
     *  @sa HTTPServer_sendResponse()
     */
    extern void HTTPServer_sendErrorResponse(int s, int status);

    /**
     *  @brief Begin the process of sending a chunked response to a client
     *
     *  This function is typically called by a URL Handler, in response to
     *  handling a URL request.
     *
     *  @param[in]  s       TCP/IP socket connected to a client
     *  @param[in]  status  Status Code associated with the response
     *  @param[in]  type    Content-type of the response
     *
     *  @httpserver_init_precondition
     *
     *  @remarks    HTTPServer_sendResponseChunked() starts the process of
     *              sending a chunked reply.  It sends a line with the
     *              status field (e.g. "Status: 200 OK"), followed by the
     *              "Transfer-Encoding: chunked\r\n\r\n" field.  The rest
     *              of the response can then be sent using
     *              HTTPServer_sendChunk().
     *
     *  @sa HTTPServer_sendChunk()
     */
    extern void HTTPServer_sendResponseChunked(int s, int status,
            const char * type);

    /**
     *  @brief      Continue and complete the process of sending a chunked
     *              response to a client
     *
     *  This function is typically called by a URL Handler, in response to
     *  handling a URL request.
     *
     *  @param[in]  s       TCP/IP socket connected to a client
     *  @param[in]  buf     Response buffer
     *  @param[in]  len     Number of bytes in the response buffer @c buf
     *
     *  @httpserver_init_precondition
     *
     *  @remarks    HTTPServer_sendChunked() sends the requisite
     *              ASCII-encoded hex size of the data being sent (@c
     *              len), followed by the data in @c buf.
     *
     *  @remarks    To indicate the end of a chunked reply, call
     *              HTTPServer_sendChunk() with @c len set to zero.
     *
     *  @sa HTTPServer_sendChunkedResponse()
     */
    extern void HTTPServer_sendChunk(int s, const void * buf, size_t len);

    /**
     *  @brief Begin the HTTP Server's main processing loop.
     *
     *  @param[in]  srv     Handle to the server
     *  @param[in]  addr    Address information for server startup
     *  @param[in]  len     Length of the address information structure
     *  @param[in]  backlog Maximum number of pending connections to server
     *
     *  @retval     0       Server received stop command
     *  @retval     -1      Server shutdown unexpectedly
     *  @retval     <-1     See HTTPServer_E error codes
     *
     */
    extern int HTTPServer_serveSelect(HTTPServer_Handle srv,
            const struct sockaddr *addr, int len, int backlog);

    /**
     *  @brief Stop a currently running server
     *
     *  In order to stop the server using this function, this must be called
     *  from an outside thread.
     *
     *  @param[in]  srv     Handle to the server being stopped
     *  @param      timeout The time in which the server is expected to halt
     *
     */
    extern bool HTTPServer_stop(HTTPServer_Handle srv, uint32_t timeout);

    /** @cond INTERNAL */
    /* internal services not quite ready to expose just yet */
    extern int (*HTTPServer_errorResponseHook)(int s, int status);

    extern void HTTPServer_requestSend(URLHandler_Session urls);

    extern void HTTPServer_stopSession(URLHandler_Session urls);
    /** @endcond */

    /**
     *  @brief Obtain the session's security status.
     *
     *  @param      sess    A handle containing session state.
     *
     *  @sa HTTPServer_enableSecurity()
     */
    extern bool HTTPServer_isSessionSecure(URLHandler_Session sess);

    /*! @} */
    #ifdef __cplusplus
    }
    #endif

    #endif

  • Christian,

    Thank you for posting your solution to help out the community. Very gracious of you.

    I'm sorry we were unable to help on this one.

    ~Ramsey

**Attention** This is a public forum