Working with GET-POST Data



Click here for a larger image.

Environment: ASP.NET, MFC/C++, ISAPI, ISAPI Extensions

Introduction

This article presents a way to retrieve the GET-POST data from a form in an ISAPI extension. Two helpful collections classes of parameters are also provided. Because a non-MFC ISAPI extension is more reliable regarding the speed and the simultaneous number of connections, a non-MFC version is also included.

Functionality

Both the MFC and non-MFC versions use Vector-, Map-, and String STL-based classes, with non-MFC code inside. In the MFC version, the string collection is based on the _bstr_t type. In the non-MFC version, the string collection is based on the STL String type. So, the MFC version is using the ISAPI MFC-based macros to retrieve the server variables and parameters data while the non-MFC version uses the WriteClient and ServerSupportFunction HTTP functions.

The default method writes to the browser a complex form with check boxes, edit boxes, radio buttons, text area—even a file type edit box. The idea is to receive all the POST parameters into the same DLL extension. The form is loaded from an HTML string resource using the LoadLongResource helper function. This reduces the time needed to build the page because the string is loaded into memory on the first call of the extension. How to use the HTML string resources in your Visual Studio project it is show in my ADO Data access from ISAPI article.

The GET data is received very easily because that type of data is sent from the browser to the server using the URL. The POST data variables are transparent to the user and it is possible to transfer large amounts of data. For more information about GET/POST data, see my HTTP GET-POST utility article.

MFC Version

The C++ classes used to store parameters from the data collection are Twin and TwinVector. The Default method of the ISAPI MFC version writes to the client browser the IDR_HTML_FORM resource. FormRequest is the method that receives the control after you click on the "Submit Query" button.

void CPostDataExtension::FormRequest(CHttpServerContext* pCtxt,
                                     void* pVoid, DWORD dwBytes)
{
    //build the STL collection from server variables and POST data
    TwinVector    vecServerCtx(pCtxt, (LPTSTR)pVoid);

    //write on browser stream the server context variables
    WriteServerData(pCtxt);

    //write on browser stream the STL collection of
    //server context variables and POST data
    WriteServerVar(pCtxt, vecServerCtx);
}

A little problem is to get the control from the DLL entry point to FormRequest method. Under the MFC, that is done very easily, by using the macros:

DEFAULT_PARSE_COMMAND(FormRequest,   CPostDataExtension)
ON_PARSE_COMMAND(FormRequest,        CPostDataExtension, ITS_RAW)

To correctly know what method will receive the POST data, the MFC wrapper must receive from the HTML form one hidden parameter, which must be in the first place after the FORM HTML tag:

<form action="PostData.dll?" method=post>
<input TYPE=hidden NAME="MfcISAPICommand" VALUE="FormRequest">

In the WriteServerVar helper function, the server context variables collection is written on the HTTP stream. It's possible to directly obtain the value of a needed parameter:

bstrValue = vecServerCtx.Find(L"Filename").
for (itVec = vecServerCtx.begin(); itVec != vecServerCtx.end();
                                   itVec++)
    *pCtxt    <<    <itvec->GetName()
              << " = " <<<itvec->    GetValue()
              << "br";



Click here for a larger image.

In the same WriteServerVar helper function, the POST data collection is written to the HTTP stream in this way:

bstrToken    = L"DATA";
index        = vecServerCtx.Find(bstrToken);
if (index > -1)
{
    map = vecServerCtx[index].GetValueAsMap();
    if (!map.empty())    //we have values
    for (itMap = map.begin(); itMap != map.end(); itMap++) 
        *pCtxt    <<    (*itMap).first     << " = " 
                  <<    (*itMap).second    << "br";
}



Click here for a larger image.

It's possible to directly obtain the value of a needed parameter:

*pCtxt << "Filename = " << map[L"Filename"] << "br".

The TwinVector class offers the VARIANT GetVariant() method and TwinVector(VARIANT varSafe) constructor, to easily transport the collection over a network between COM+ components.

Non-MFC Version

The non-MFC version is based on the MSDN article regarding at GET-POST data in ISAPI extensions.

The C++ extension receives the entry point in the DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK pECB ) method.

Here it launches the Run method of the CWriteFormExtension class—there is only one running object in our ISAPI extension.

The C++ classes used to keep the parameters in the data collection are MultipartParser and MultipartEntry. The cParser variable of the inherited Map STL type receives the entire collection of POST data. That is done in the Initialize method. GetParam is a helper method that returns the value of a needed parameter.

String CWriteFormExtension::GetParam(MultipartParser& cParser,
                            String sName)
{
    String           sValue;    //the output string
    MultipartEntry*  pEntry  = cParser[sName.c_str()];

    if(pEntry != NULL)          //we have data
    {
        sValue = (LPCTSTR) pEntry->Data();
                                //get value from collection
        int nLen = sValue.size();

        if(sValue[nLen - 1] == '\n' && sValue[nLen - 2] == '\r')
        sValue = sValue.substr(0, nLen - 2);
    }
    return sValue;
}

This is the result of the Run method:



Click here for a larger image.

The LoadLongResource private function is a little modified, compared with the MFC version. The input/output str string parameter is of the STL string type. In the szPath char variable, we must put the name of the DLL file to load the correct resource library.

BOOL CWriteLayoutExtension::LoadLongResource(String &str, UINT nID)
{
    HRSRC               hRes;
    BOOL                bResult            = FALSE;
    CHAR                szPath[MAX_PATH];
    
    strcpy(szPath, "WriteForm.dll");
    HINSTANCE hInst = LoadLibrary(szPath);

    //if you want standard HTML type
    hRes = FindResource(hInst, MAKEINTRESOURCE(nID), RT_HTML);
    if (hRes == NULL)
    {
         //trace error
        str = "Error: Resource could not be found\r\n";
    }
    else
    {
        DWORD dwSize = SizeofResource(hInst, hRes);
        if (dwSize == 0)
        {    
            str.empty();
            bResult = TRUE;
        }
        else
        {
            HGLOBAL hGlob = LoadResource(hInst, hRes);
            if (hGlob != NULL)
            {
                LPVOID lpData = LockResource(hGlob);
                if (lpData != NULL)
                {
                    str            = (LPCTSTR)lpData;
                    bResult        = TRUE;
                }
                FreeResource(hGlob);
            }
        }
        if (!bResult)
        str = "Error: Resource could not be load\r\n";
    }
    return bResult;
}

Downloads

Download ISAPI MFC source files - 34 Kb
Download ISAPI Non-MFC source files - 107 Kb


Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility. Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

  • Companies undertaking an IT project need to find the right balance between cost and functionality. It's important to start by determining whether to build a solution from scratch, buy an out-of-the-box solution, or a combination of both. In reality, most projects will require some system tailoring to meet business requirements. Decision-makers must understand how much software development is enough and craft a detailed implementation plan to ensure the project's success. This white paper examines the different …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date