www.pudn.com > Firewall_PNE_3_3.zip > fwWebHttpRpmWmbPost.c, change:2009-03-16,size:18298b


/* httpRpmWmbPost.c - WindMark POST request processing modules */

/* Copyright 2001-2004 Wind River Systems, Inc. */

/*
modification history
--------------------
01l,13aug04,zhu  allow setting all in POST
01k,11aug04,zhu  customized for firewall webscreen, porting to dual stack
01j,27dlr04,dlr  Do not destroy the optional GET session if not created in httpRpmWmbPostExec
01i,06may04,vmk  error handling for wmbTransactionProcess ( spr#91378)
01h,27apr04,adb  replaced all buffer size constants with kMagicMarkupBufferSize
01g,10mar04,adb  NULL instance to empty sting conversion
01f,03mar04,gsr  for inline instancing set operation SPR#91008
01e,16jan04,jws  remove per project dependencies
01d,18aug03,jws  documentation updates
01c,24jul03,jws  SPR 89657 work and general clean-up
01b,16jun03,adb  introduced tempBuf in lclBuildSetTrans
01a,06nov01,jc   initial creation.
*/

/*
DESCRIPTION

This library contains request processing modules (RPMs) for setting
Windmarks via an http POST.  These standard RPMs can be associated with URLs
using the WMIT project configuration tool.

In addition, the function httpRpmWmbPostExec() can be called by a user custom
RPM to do Windmark POST processing with various options not available using the
"standard" RPMs.  For example, a custom RPM which would set only posted items
whose value has changed could be as simple as:
\cs
short customRPM
    (
    HTTP_REQ_ID reqId
    )
    {
    return httpRpmWmbPostExec(reqId,RPM_CHANGE_ONLY_SET);
    }
\ce
Before the functions in this library are called to process a request, some
pre-processing of the data must be done.  The functions httpRpmUpload() or
httpRpmPost() copy any name=value duplets in the CGI stream (the http request)
to the server's environment.  Functions here will look for WindMarks in that
environment, and if found, will access the backplane to update their values.
So, for example, the following sequence could be used to register
httpRpmWmbPost() with the server for the URL /url/:
\cs
    httpRpmConfAdd (HTTP_M_POST, "/url/", httpRpmPost)
    httpRpmConfAdd (HTTP_M_POST, "/url/", httpRpmWmbPost)
\ce
Registration is normally done automatically during server initialization
in code generated by the tool WMIT.  RPMs are invoked seriatim until one
does not return RPM_OK.  RPMs in this library return RPM_OK, only if they
do not recognize the Content-Type of the request.

Functions in this library recognize POSTs with Content-Type of
"application/x-www-form-urlencoded" or "multipart/form-data".  These are the
standard types for forms and multi-part forms, respectively.


INCLUDE FILES: httpLib.h,httpRpms.h

*/

#undef DEBUG_INFO


/* system header files */

#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

/* WM header files */

#include "wrn/wm/http/httpLib.h"
#include "wrn/wm/http/httpRpms.h"
#include "wrn/wm/http/private/httpReq.h"
#include "wrn/wm/http/private/httpInt.h"
#include "wrn/wm/http/httpWmbExpandInstance.h"


/* WM project header files */

#if 0
#include "wmw_httpconf.h"
#endif

#include "fwWebDevice.h"

/* externals - will move to header file(s) */

IMPORT STATUS (*pWmmErrorLogStart)(INT32);
IMPORT STATUS (*pWmmErrorLogEnd)(INT32);
IMPORT ubyte4  wmVarMagicMarkupBufferSize;

/* constants */


/* locals */

LOCAL STATUS lclBuildSetTrans(HTTP_REQ_ID, WMB_SESSION_T *, WMB_TID_T,
                              WMB_SESSION_T *);

LOCAL short   lclReportError();
LOCAL sbyte * lclParseInstanceInfo(sbyte * fullWindMarkName);

#if 0  /* unused routines */
LOCAL STATUS lclBuildGetTrans(HTTP_REQ_ID,WMB_SESSION_T *,WMB_TID_T);
LOCAL STATUS lclGetToSetTrans(HTTP_REQ_ID,WMB_SESSION_T *,WMB_TID_T,int);
LOCAL BOOL lclValueMatches
    (
    WMB_OBJ_T obj,     /* object to check */
    sbyte *   pVal     /* value to check against */
    );

LOCAL WMB_OBJ_T lclObjCut
    (
    WMB_TID_T tid,
    WMB_OBJ_T obj
    );

/* debuggering */

LOCAL void lclDumpTrans(WMB_TID_T,char *);
#endif

/* format string for error reporting */

static char errFmt[] = "httpRpmWmbPost errno = %d\r\n";


/* prototypes missing from header files */

WM_BUFFER_T * wmbObjectValueBufferGet
    (
    WMB_OBJ_T       obj
    );



/**************************************************************************
*
* fwWebHttpRpmWmbPost - process Windmarks in a POST
*
* This is the routine that actually sets WindMarks.  It underlies
* httpRpmWmbPost() and httpRpmWmbBestEffortPost().  Users who write their
* own custom RPM module would typically call this function to do the
* actual Windmark processing.
*
* If <flags> is 0, all items in the POST will be set.  Otherwise, <flags>
* may be any combination of:
* \is
* \i RPM_BEST_EFFORT_SET
* The set transaction is done on a "best effort" basis and will succeed
* even if some items cannot be set.
* \i RPM_CHANGE_ONLY_SET
* Set only those items whose value will change.  If, for some reason, the
* current value of an item cannot be determined, it will be set.
* \ie
*
* RETURNS: RPM_OK if the POST Content-Type is inappropriate; RPM_DONE if
* the post processing was successful; RPM_ERROR otherwise.
*/

short fwWebHttpRpmWmbPost
    (
    HTTP_REQ_ID reqId  /* handle of the active request */
    )
    {
    int         flags=0;   /* processing options */
    const sbyte *     contentEnc;
    WMB_SESSION_T *   pSession = NULL;
    WMB_SESSION_T *   pGetSession = NULL;
    WMB_TID_T         tid = NULL;
    WMB_OBJ_T         pObj;
    ubyte4            trans_flags;
    BOOL              doSet;

	/* Set up the transaction flag(s) */

	trans_flags = (flags & RPM_BEST_EFFORT_SET)  ?  WMB_TM_NOUNDO : 0;

	/* Check the header for correct content type */

    contentEnc = httpMimeHdrGet(reqId, HDR_IN, "Content-Type");

    if (strcmp(contentEnc, "application/x-www-form-urlencoded") &&
        strcmp(contentEnc, "multipart/form-data"))
        {
        return RPM_OK; /* some other RPM may deal with it */
        }

    /* create a WMB session */

    if (OK != wmbSessionCreate (httpGetWmbComp(), 0,
                                WMB_SESSION_NO_DEF_TRANSACTION, &pSession))
        {
        return lclReportError ();
        }

    /*
     * A second session may be created if we are doing selective set's.
     * It is not an error if this session cannot be created.
     */

    if (flags & RPM_CHANGE_ONLY_SET)
        {
        wmbSessionCreate(httpGetWmbComp(),0,0,&pGetSession);
        }

    if (pWmmErrorLogStart)  pWmmErrorLogStart(pSession->id);

    /*
     * Create a transaction in which to store the WindMark objects.
     * If this fails, report the error, but continue so that we can
     * clean-up properly.
     */

    doSet = ((wmbTransactionCreate(pSession, 0, trans_flags, &tid) == OK) &&
             (lclBuildSetTrans(reqId, pSession, tid, pGetSession) == OK))
            ?  TRUE : FALSE;

    if (!doSet)  lclReportError();  /* do now to report proper errno */



#if 0
    lclDumpTrans(tid,"Before Set");
#endif

    if (doSet)  /* If nothing is wrong, we now do a SET transaction. */
        {
	    if (wmbTransactionProcess(tid, CMD_SET_K) != OK)
            {
            pObj = wmbTransactionErrQGet( tid );
		    if (NULL != pObj )
                {
                httpWindMarkSetFailed(reqId, wmbObjectNamePtrGet(pObj), wmbTransactionStatusGet(tid));
                }
            else
                {
                wmLogPrintf ("httpRpmWmbPost: failed to process transaction\n");
                }
                
            doSet = FALSE;
            }
        else
        {
        fwWebReachEndSet();
        /*
         * httpPostReply() is a user supplied function which sends some
         * kind of POST response message to the client.  It might need
         * to know the session we're in.
         */

        reqId->pSession = pSession;
        httpPostReply (reqId, HTTP_OK);
        }
        }

    if (pWmmErrorLogEnd)  pWmmErrorLogEnd(pSession->id);

    /*
     * Clean up.  There is really no point in checking for errors
     * here.
     */

    if (NULL != pGetSession)
    	wmbSessionDestroy(pGetSession);

    wmbTransactionEnd(tid);
    wmbSessionDestroy(pSession);

    return (doSet)  ?  RPM_DONE : RPM_ERROR;
    }


/**************************************************************************
*
* lclBuildSetTrans - build transaction for setting Windmarks
*
* This routine searches an http request for form element names and
* adds them to a wmb transaction.  If <pGetSession> is not NULL, and buffer
* space can be allocated, it will do a get on each WindMark and only add it
* to the transaction if it's value will change.
*
* Because of session and transaction interactions, we must do our get's in
* a different session than the one for the set transaction we are building.
*
* RETURNS: OK or ERROR
*/


LOCAL STATUS lclBuildSetTrans
    (
    HTTP_REQ_ID     reqId,         /* http request */
    WMB_SESSION_T * pSession,      /* session for setting */
    WMB_TID_T       tid,           /* transaction in pSession */
    WMB_SESSION_T * pGetSession    /* (optional) session for getting */
    )
    {
    sbyte *        pMagicMarkup;
    sbyte *        pVal;
    sbyte *        pInst;
    sbyte *        pStrTokState;
    sbyte *        pArgMagicMarkup;
    sbyte4         instLen;
    void *         pBuffer;
    sbyte *        tempBuf;
    sbyte4         written;
    WMB_OBJ_T      obj;
    HTTP_GEN_LIST_ENTRY_ID  lstEntry;
    static char    sUnchecked[] = "OFF";
    sbyte    inlineMark[kMagicMarkupBufferSize + 1]; /* should be max instance length ??*/


    if (NULL == reqId || NULL == reqId->argListId)
        return wmError (ERROR_GENERAL_NULL_POINTER, errFmt);

    lstEntry = httpGenListFind (reqId->argListId, "END_OF_HEADERS");

    if (lstEntry == NULL)
        return wmError(0, errFmt);

    /*
     * We use the memory pool associated with this HTTP request because
     * it should be more efficient than a general malloc().
     */

    tempBuf = memPoolAlloc(reqId->memPool,httpMaxTempBufSize);

    if (tempBuf == NULL)
        return wmError(0, errFmt);

    /* Even if this next allocation fails, it is safe to proceed. */

    pBuffer = (pGetSession)  ?  memPoolAlloc(reqId->memPool,
                                             wmVarMagicMarkupBufferSize)
                                : NULL;

    while (httpGenListIterator(reqId->argListId, &lstEntry) != NULL)
        {
        pMagicMarkup = httpGenListIdGet (lstEntry);

        /*
         * tempBuf has sufficient size and pMagicMarkup does point to
         * a null terminated string
         */

        STRCPY (tempBuf, pMagicMarkup);


       /* Check for braces */
       if (NULL != (pInst = strstr(tempBuf,"{[")))
           {
            /* expand the instances */
             httpExpandInstance (pSession, pInst, inlineMark);
             if (inlineMark[0] == '\0')
                return (wmError (ERROR_GENERAL, errFmt));
             tempBuf[(pInst - tempBuf) - 1] = '\0';

           }
        else if (NULL != (pInst = strstr(tempBuf,"{(")))
            {
            /* expand the instances */
             httpExpandInstance (pSession, pInst, inlineMark);
             if (inlineMark[0] == '\0')
                return (wmError (ERROR_GENERAL, errFmt));
             tempBuf[(pInst - tempBuf) - 1] = '\0';

            }
        else
            {

            /* look for instance information (dotted OID suffix or parenthesis) */
            pInst = lclParseInstanceInfo (tempBuf);
            STRCPY(inlineMark, (NULL != pInst) ? pInst : "");

            }

        instLen = strlen(inlineMark) + 1;

        /*
         * Deal with the only special WindMark: the checkbox manager.
         * Arguments of this "Windmark" are a list of all the checkboxes
         * in the form.  We use this list to determine which boxes are
         * not checked.
         */

        if (0 == strcmp(tempBuf, "CheckBoxManager"))
            {
            pArgMagicMarkup = httpGetEnv (reqId, pMagicMarkup);

            /*
             * Parse comma delimited list of checkboxes.  This is a
             * destructive parse which renders the list unusable.
             */

            for (pArgMagicMarkup = STRTOK_REENTRANT(pArgMagicMarkup,
                                                    ",",&pStrTokState);
                 pArgMagicMarkup != NULL;
                 pArgMagicMarkup = STRTOK_REENTRANT(NULL,
                                                    ",", &pStrTokState)
                )
                {

                if (NULL == httpGetEnv (reqId, pArgMagicMarkup))
                    {

                    /*
                     * If pArgMagicMarkup is not found in the environment
                     * (CGI stream), set it to "OFF".  We may not do this
                     * if it is already "OFF".
                     */

                    if (pBuffer)   /* set only if value will change */
                        {

                        if (wmbDataStringGet(pGetSession,pArgMagicMarkup,
                                     inlineMark,instLen,
				                     pBuffer,wmVarMagicMarkupBufferSize,
				                     &written) == OK)
     				        {

				            if (strcmp(pBuffer,sUnchecked) == 0)  continue;
				            }
				        }

                    if ((OK != wmbObjectCreate(tid, pArgMagicMarkup,
                                               inlineMark, instLen, &obj)) ||
                        (OK != wmbObjectValueCreate(obj, sUnchecked,
                                                    sizeof(sUnchecked),
                                                    DATATYPE_STRING_K, TRUE)))
                        {
                        httpWindMarkSetFailed(reqId, pArgMagicMarkup, errno);
                        }
                    }

                }
            }
        else if (wmbDataExists(pSession, tempBuf))
            {
            pVal = httpGetEnv(reqId, pMagicMarkup);

            /*
             * Create object (memory representation of a WindMark)
             * that will be added to transaction list.  The object
             * might not be created if its value would not change.
             */

            if (pBuffer)  /* set only if value will change */
                {

                if (wmbDataStringGet(pGetSession,tempBuf,inlineMark,
                                     instLen,
				                     pBuffer,wmVarMagicMarkupBufferSize,
				                     &written) == OK)
				    {
				    /*
				     * Unfortunately, "written" is not necessarily the
				     * size of the string returned, so we do a strcmp().
				     */

				    if (strcmp(pBuffer,pVal) == 0)  continue;
				    }
                }

            if ((OK != wmbObjectCreate(tid, tempBuf, inlineMark, instLen, &obj)) ||
                (OK != wmbObjectValueCreate(obj,pVal,strlen(pVal) + 1,
                                            DATATYPE_STRING_K,TRUE)))
                {
                httpWindMarkSetFailed(reqId, pMagicMarkup, errno);
                }

            }
        else   /* WindMark does not exist in wmb */
            {
            httpWindMarkSetFailed(reqId, pMagicMarkup, errno);
            }
        } /* while */

    /*
     * We don't really have to free stuff here because it will be
     * freed when the request is ended, but it is not a good idea
     * to let garbage accumulate.
     */

    memPoolFree(reqId->memPool,tempBuf);
    if (pBuffer)  memPoolFree(reqId->memPool,pBuffer);

    return OK;
    }   /* lclBuildSetTrans */


/**************************************************************************
*
* lclReportError - return RPM_ERROR and display error message
*
* This is an error reporting function used by the local RPMs.  <errno>
* should have already been set when we get here, so we pass a zero
* to wmError() which won't change <errno>.
*
* RETURNS: RPM_ERROR
*/

LOCAL short lclReportError()
    {

    logErrorMsg (errFmt,errnoGet());
    wmError (0, errFmt);

    return RPM_ERROR;
    }

/**************************************************************************
*
* lclParseInstanceInfo - look for instance information in a posted WindMark
*
* This function looks for instance information in a posted WindMark. Currently
* there are two types of instance data supported:  a dotted OID following the
* WindMarks' name (such as ifPhysAddr.2.3.1), and a string delimited by
* parenthesis (such as myFormat(1.12x)).  On the first example, the instance
* data is considered to be the string "2.3.1" and in the second, "1.12x".
*
* This function takes a pointer to the full WindMark name as its first parameter,
* parses it for either type of instance information, and if found, a pointer
* to it will be returned.
*
* All processing is done "in place" so no new memory is allocated.
*
*.NOMANUAL
*/

LOCAL sbyte *  lclParseInstanceInfo
    (
    sbyte * fullWindMarkName
    )
    {
    sbyte * pInst;
    sbyte * pStrTokState = NULL;

    /* look for a dot or an opening parens */

    STRTOK_REENTRANT (fullWindMarkName, ".(", &pStrTokState);
    pInst = pStrTokState;

    /* look for closing parens - don't care for result, just to overwrite it */

    pStrTokState = STRTOK_REENTRANT (NULL, ")", &pStrTokState);

    return pInst;
    }



#if 0

/**************************************************************************
*
* lclDumpTrans - print transaction info for debugging
*
* RETURNS:
*/

LOCAL void lclDumpTrans
    (
    WMB_TID_T tid,
    char *    title
    )
    {
    WMB_OBJ_T       obj;
    sbyte4          written;
    sbyte *         pName;
    STATUS          s;
    static sbyte    temp[512];

    if (title)  printf("-------- %s --------\r\n",title);

    obj = wmbTransactionHeadGet (tid);

    while (! wmbObjectBad(obj))
        {
        temp[0] = '\0';
        pName   = wmbObjectNameGet  (obj);

        s = wmbObjectExport(obj,temp,sizeof(temp),DATATYPE_STRING_K,&written);

        if (s == OK)
            {
            printf("%s [%d bytes] = %s\r\n", pName, written, temp);
            }
        else
            {
            printf("%s [ERROR]\r\n", pName);
            }

        obj = wmbObjectListNextGet (obj);
        }

#if 0
    wmOidPrint(table->rowOidSfx, "instance");
#endif

    return ;
    }

#endif