Пример #1
0
void
xmlrpc_parse_response2(xmlrpc_env *    const envP,
                       const char *    const xmlData,
                       size_t          const xmlDataLen,
                       xmlrpc_value ** const resultPP,
                       int *           const faultCodeP,
                       const char **   const faultStringP) {
/*----------------------------------------------------------------------------
  Given some XML text, attempt to parse it as an XML-RPC response.

  If the response is a regular, valid response, return a new reference
  to the appropriate value as *resultP and return NULL as
  *faultStringP and nothing as *faultCodeP.

  If the response is valid, but indicates a failure of the RPC, return the
  fault string in newly malloc'ed space as *faultStringP and the fault
  code as *faultCodeP and nothing as *resultP.

  If the XML text is not a valid response or something prevents us from
  parsing it, return a description of the error as *envP and nothing else.
-----------------------------------------------------------------------------*/
    xml_element * response;

    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);

    /* SECURITY: Last-ditch attempt to make sure our content length is legal.
    ** XXX - This check occurs too late to prevent an attacker from creating
    ** an enormous memory block, so you should try to enforce it
    ** *before* reading any data off the network. */
    if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            envP, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC response too large.  Our limit is %u characters.  "
            "We got %u characters",
            xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID), xmlDataLen);
    else {
        xmlrpc_env env;
        xmlrpc_env_init(&env);

        xml_parse(&env, xmlData, xmlDataLen, &response);

        if (env.fault_occurred)
            setParseFault(envP, "Not valid XML.  %s", env.fault_string);
        else {
            /* Pick apart and verify our structure. */
            if (xmlrpc_streq(xml_element_name(response), "methodResponse")) {
                parseMethodResponseElt(envP, response,
                                       resultPP, faultCodeP, faultStringP);
            } else
                setParseFault(envP, "XML-RPC response must consist of a "
                              "<methodResponse> element.  "
                              "This has a <%s> instead.",
                              xml_element_name(response));
            
            xml_element_free(response);
        }
        xmlrpc_env_clean(&env);
    }
}
Пример #2
0
void
processCall2(const registry * const  registryP,
             FILE *           const  callFileP,
             unsigned int     const  callSize,
             bool             const  sendCookie,
             string           const& authCookie,
             FILE *           const  respFileP) {

    if (callSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        throw(xmlrpc_c::fault(string("XML-RPC call is too large"),
                              fault::CODE_LIMIT_EXCEEDED));
    else {
        string const callXml(getHttpBody(callFileP, callSize));

        string responseXml;

        try {
            registryP->processCall(callXml, &responseXml);
        } catch (exception const& e) {
            throw(httpError(500, e.what()));
        }
        
        writeNormalHttpResp(respFileP, sendCookie, authCookie, responseXml);
    }
}
Пример #3
0
static void test_nesting_limit (void)
{
    xmlrpc_env env;
    xmlrpc_value *val;

    xmlrpc_env_init(&env);
    
    /* Test with an adequate limit for a result value which is an
       array which contains an element which is a struct, whose values
       are simple: 3.
    */
    xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 3);
    val = xmlrpc_parse_response(&env,
                                good_response_xml, strlen(good_response_xml));
    TEST_NO_FAULT(&env);
    TEST(val != NULL);
    xmlrpc_DECREF(val);

    /* Test with an inadequate limit. */
    xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2);
    val = xmlrpc_parse_response(&env,
                                good_response_xml, strlen(good_response_xml));
    TEST_FAULT(&env, XMLRPC_PARSE_ERROR); /* BREAKME - Will change. */
    TEST(val == NULL);

    /* Reset the default limit. */
    xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, XMLRPC_NESTING_LIMIT_DEFAULT);
    TEST(xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID)
         == XMLRPC_NESTING_LIMIT_DEFAULT);

    xmlrpc_env_clean(&env);
}
Пример #4
0
static xmlrpc_value *
convert_params(xmlrpc_env *        const envP,
               const xml_element * const elemP) {
/*----------------------------------------------------------------------------
   Convert an XML element representing a list of parameters (i.e.  a
   <params> element) to an xmlrpc_value of type array.  Note that an
   array is normally represented in XML by a <value> element.  We use
   type xmlrpc_value to represent the parameter list just for convenience.
-----------------------------------------------------------------------------*/
    xmlrpc_value *array, *item;
    int size, i;
    xml_element **params, *param, *value;

    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(elemP != NULL);

    /* Set up our error-handling preconditions. */
    array = item = NULL;

    /* Allocate an array to hold our parameters. */
    array = xmlrpc_build_value(envP, "()");
    XMLRPC_FAIL_IF_FAULT(envP);

    /* We're responsible for checking our own element name. */
    CHECK_NAME(envP, elemP, "params");    

    /* Iterate over our children. */
    size = xml_element_children_size(elemP);
    params = xml_element_children(elemP);
    for (i = 0; i < size; ++i) {
        unsigned int const maxNest = xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID);

        param = params[i];
        CHECK_NAME(envP, param, "param");
        CHECK_CHILD_COUNT(envP, param, 1);

        value = xml_element_children(param)[0];

        CHECK_NAME(envP, value, "value");

        xmlrpc_parseValue(envP, maxNest, value, &item);
        XMLRPC_FAIL_IF_FAULT(envP);

        xmlrpc_array_append_item(envP, array, item);
        xmlrpc_DECREF(item);
        item = NULL;
        XMLRPC_FAIL_IF_FAULT(envP);
    }

 cleanup:
    if (envP->fault_occurred) {
        if (array)
            xmlrpc_DECREF(array);
        if (item)
            xmlrpc_DECREF(item);
        return NULL;
    }
    return array;
}
Пример #5
0
static void
processCall(TSession *            const abyssSessionP,
            size_t                const contentSize,
            xmlrpc_call_processor       xmlProcessor,
            void *                const xmlProcessorArg,
            bool                  const wantChunk,
            ResponseAccessCtl     const accessControl,
            const char *          const trace) {
/*----------------------------------------------------------------------------
   Handle an RPC request.  This is an HTTP request that has the proper form
   to be an XML-RPC call.

   The text of the call is available through the Abyss session
   'abyssSessionP'.

   Its content length is 'contentSize' bytes.
-----------------------------------------------------------------------------*/
    xmlrpc_env env;

    if (trace)
        fprintf(stderr,
                "xmlrpc_server_abyss URI path handler processing RPC.\n");

    xmlrpc_env_init(&env);

    if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            &env, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC request too large (%u bytes)", (unsigned)contentSize);
    else {
        xmlrpc_mem_block * body;
        /* Read XML data off the wire. */
        getBody(&env, abyssSessionP, contentSize, trace, &body);
        if (!env.fault_occurred) {
            xmlrpc_mem_block * output;

            /* Process the RPC. */
            xmlProcessor(
                &env, xmlProcessorArg,
                XMLRPC_MEMBLOCK_CONTENTS(char, body),
                XMLRPC_MEMBLOCK_SIZE(char, body),
                abyssSessionP,
                &output);
            if (!env.fault_occurred) {
                /* Send out the result. */
                sendResponse(&env, abyssSessionP, 
                             XMLRPC_MEMBLOCK_CONTENTS(char, output),
                             XMLRPC_MEMBLOCK_SIZE(char, output),
                             wantChunk, accessControl);
                
                XMLRPC_MEMBLOCK_FREE(char, output);
            }
            XMLRPC_MEMBLOCK_FREE(char, body);
        }
Пример #6
0
void 
xmlrpc_parse_call(xmlrpc_env *    const envP,
                  const char *    const xmlData,
                  size_t          const xmlDataLen,
                  const char **   const methodNameP,
                  xmlrpc_value ** const paramArrayPP) {
/*----------------------------------------------------------------------------
  Given some XML text, attempt to parse it as an XML-RPC call.
  Return as *methodNameP the name of the method identified in the call
  and as *paramArrayPP the parameter list as an XML-RPC array.
  Caller must free() and xmlrpc_DECREF() these, respectively).
-----------------------------------------------------------------------------*/
    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);
    XMLRPC_ASSERT(methodNameP != NULL && paramArrayPP != NULL);

    /* SECURITY: Last-ditch attempt to make sure our content length is
       legal.  XXX - This check occurs too late to prevent an attacker
       from creating an enormous memory block, so you should try to
       enforce it *before* reading any data off the network.
     */
    if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            envP, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC request too large.  Max allowed is %u bytes",
            (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID));
    else {
        xml_element * callElemP;
        parseCallXml(envP, xmlData, xmlDataLen, &callElemP);
        if (!envP->fault_occurred) {
            parseCallChildren(envP, callElemP, methodNameP, paramArrayPP);

            xml_element_free(callElemP);
        }
    }
    if (envP->fault_occurred) {
        /* Should not be necessary, but for backward compatibility: */
        *methodNameP  = NULL;
        *paramArrayPP = NULL;
    }
}
Пример #7
0
void
xmlrpc_parse_value_xml(xmlrpc_env *    const envP,
                       const char *    const xmlData,
                       size_t          const xmlDataLen,
                       xmlrpc_value ** const valuePP) {
/*----------------------------------------------------------------------------
   Compute the xmlrpc_value represented by the XML document 'xmlData' (of
   length 'xmlDataLen' characters), which must consist of a single <value>
   element.  Return that xmlrpc_value.

   We call convert_array() and convert_struct(), which may ultimately
   call us recursively.  Don't recurse any more than 'maxRecursion'
   times.

   This isn't generally useful in XML-RPC programs, because such programs
   parse a whole XML-RPC call or response document, and never see the XML text
   of just a <value> element.  But a program may do some weird form of XML-RPC
   processing or just borrow Xmlrpc-c's value serialization facilities for
   something unrelated to XML-RPC.  In any case, it makes sense to have an
   inverse of xmlrpc_serialize_value2(), which generates XML text from an
   xmlrpc_value.
-----------------------------------------------------------------------------*/
    xmlrpc_env env;

    xml_element * valueEltP;

    XMLRPC_ASSERT_ENV_OK(envP);
    XMLRPC_ASSERT(xmlData != NULL);

    xmlrpc_env_init(&env);

    xml_parse(&env, xmlData, xmlDataLen, &valueEltP);

    if (env.fault_occurred) {
        setParseFault(envP, "Not valid XML.  %s", env.fault_string);
    } else {
        if (xmlrpc_streq(xml_element_name(valueEltP), "value")) {
            unsigned int const maxRecursion = (unsigned int)
                xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID);
            xmlrpc_parseValue(envP, maxRecursion, valueEltP, valuePP);
        } else
            setParseFault(envP, "XML-RPC value XML document must consist of "
                          "a <value> element.  This has a <%s> instead.",
                          xml_element_name(valueEltP));
        xml_element_free(valueEltP);
    }
    xmlrpc_env_clean(&env);
}
Пример #8
0
static void
processCall(TSession *        const abyssSessionP,
            size_t            const contentSize,
            xmlrpc_registry * const registryP,
            bool              const wantChunk,
            const char *      const trace) {
/*----------------------------------------------------------------------------
   Handle an RPC request.  This is an HTTP request that has the proper form
   to be one of our RPCs.

   Its content length is 'contentSize' bytes.
-----------------------------------------------------------------------------*/
    xmlrpc_env env;

    if (trace)
        fprintf(stderr,
                "xmlrpc_server_abyss URI path handler processing RPC.\n");

    xmlrpc_env_init(&env);

    if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
        xmlrpc_env_set_fault_formatted(
            &env, XMLRPC_LIMIT_EXCEEDED_ERROR,
            "XML-RPC request too large (%ld bytes)", (long)contentSize);
    else {
        xmlrpc_mem_block *body=0;
        /* Read XML data off the wire. */
        getBody(&env, abyssSessionP, contentSize, trace, &body);
        if (!env.fault_occurred) {
            xmlrpc_mem_block * output;
            /* Process the RPC. */
            output = xmlrpc_registry_process_call(
                &env, registryP, NULL,
                XMLRPC_MEMBLOCK_CONTENTS(char, body),
                XMLRPC_MEMBLOCK_SIZE(char, body));
            if (!env.fault_occurred) {
                /* Send out the result. */
                sendXmlData(&env, abyssSessionP,
                            XMLRPC_MEMBLOCK_CONTENTS(char, output),
                            XMLRPC_MEMBLOCK_SIZE(char, output),
                            wantChunk);

                XMLRPC_MEMBLOCK_FREE(char, output);
            }
            XMLRPC_MEMBLOCK_FREE(char, body);
        }
Пример #9
0
static void
parseFaultElement(xmlrpc_env *        const envP,
                  const xml_element * const faultElement,
                  int *               const faultCodeP,
                  const char **       const faultStringP) {
                  
    unsigned int const maxRecursion = (unsigned int)
        xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID);

    XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(faultElement), "fault"));

    if (xml_element_children_size(faultElement) != 1)
        setParseFault(envP, "<fault> element should have 1 child, "
                      "but it has %u.",
                      xml_element_children_size(faultElement));
    else {
        xml_element * const faultValueP =
            xml_element_children(faultElement)[0];
        const char * const elemName = xml_element_name(faultValueP);

        if (!xmlrpc_streq(elemName, "value"))
            setParseFault(envP,
                          "<fault> contains a <%s> element.  "
                          "Only <value> makes sense.",
                          elemName);
        else {
            xmlrpc_value * faultVP;

            xmlrpc_parseValue(envP, maxRecursion, faultValueP, &faultVP);
        
            if (!envP->fault_occurred) {
                interpretFaultValue(envP, faultVP, faultCodeP, faultStringP);
                
                xmlrpc_DECREF(faultVP);
            }
        }
    }
}
Пример #10
0
/**************************************
* ProcessRequest
*	Procesa una peticion
*************************************/
int XmlHandler::ProcessRequest(TRequestInfo *req,TSession * const ses)
{
	xmlrpc_env env;
	int inputLen;
	char *method;
	xmlrpc_value *params = NULL;
	timeval tv;

	Log(">ProcessRequest [uri:%s]\n",req->uri);

	//Init timer
	getUpdDifTime(&tv);

	//Creamos un enviroment
	xmlrpc_env_init(&env);

	//Si no es post
	if (req->method != m_post)
		//Mandamos error
		return XmlRpcServer::SendError(ses, 405, "Only POST allowed");

	//Obtenemos el content type
	const char * content_type = RequestHeaderValue(ses, (char*)"content-type");

	//Si no es el bueno
	 if (content_type == NULL || strcmp(content_type, "text/xml") != 0)
		return XmlRpcServer::SendError(ses, 400, "Wrong content-type");

	//Obtenemos el content length
	const char * content_length = RequestHeaderValue(ses, (char*)"content-length");

	//Si no hay 
	if (content_length == NULL)
		return XmlRpcServer::SendError(ses,411,"No content-length");

	//Obtenemos el entero
	inputLen = atoi(content_length);

	//Tiene que ser mayor que cero
	if ((inputLen < 0) || (inputLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)))
		return XmlRpcServer::SendError(ses,400,"Size limit");

	//Creamos un buffer para el body
	char * buffer = (char *) malloc(inputLen);

	if (!XmlRpcServer::GetBody(ses,buffer,inputLen))
	{
		//LIberamos el buffer
		free(buffer);

		//Y salimos sin devolver nada
		Log("Operation timedout\n");
		return 1;
	}

	//Get method name
	xmlrpc_parse_call(&env,buffer,inputLen,(const char**)&method,&params);

	Log("-ProcessRequest [method:%s]\n",method);

	//Free name and params
	free(method);
	xmlrpc_DECREF(params);

	//Generamos la respuesta
	xmlrpc_mem_block *output = xmlrpc_registry_process_call(
			&env, 
			registry, 
			NULL,
			buffer,
			inputLen
		);

	//Si todo ha ido bien
	if (!env.fault_occurred)
	{
		//POnemos el content type
		ResponseContentType(ses, (char*)"text/xml; charset=\"utf-8\"");
		//Y mandamos la respuesta
		XmlRpcServer::SendResponse(ses,200,XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output));
	} else
/*
 * This is a blocking function that merely sits on the request queue
 * for our URI and processes them one at a time.  Once a request comes
 * in, we check it for content-type, content-length, and verb.  As long
 * as the initial validations are done, we pass the request to the 
 * processRPCCall() function, which collects the body of the request
 * and processes it.  If we get an error back other than network type,
 * we are responsible for notifing the client.
 */
DWORD
DoReceiveRequests(
    IN HANDLE hReqQueue,
    const xmlrpc_server_httpsys_parms * const parmsP
    )
{
    ULONG              result;
    HTTP_REQUEST_ID    requestId;
    DWORD              bytesRead;
    PHTTP_REQUEST      pRequest;
    PCHAR              pRequestBuffer;
    ULONG              RequestBufferLength;
    xmlrpc_env          env;
    char                szHeaderBuf[255];
    long                lContentLength;

    // Allocate a 2K buffer. Should be good for most requests, we'll grow 
    // this if required. We also need space for a HTTP_REQUEST structure.
    RequestBufferLength = sizeof(HTTP_REQUEST) + 2048;
    pRequestBuffer      = (PCHAR) ALLOC_MEM( RequestBufferLength );
    if (pRequestBuffer == NULL)
    {
        return ERROR_NOT_ENOUGH_MEMORY;
    }

    pRequest = (PHTTP_REQUEST)pRequestBuffer;

    // Wait for a new request -- This is indicated by a NULL request ID.
    HTTP_SET_NULL_ID( &requestId );
    for(;;)
    {
        RtlZeroMemory(pRequest, RequestBufferLength);

        result = HttpReceiveHttpRequest(
            hReqQueue,          // Req Queue
            requestId,          // Req ID
            0,                  // Flags
            pRequest,           // HTTP request buffer
            RequestBufferLength,// req buffer length
            &bytesRead,         // bytes received
            NULL                // LPOVERLAPPED
            );

        if(NO_ERROR == result)
        {
            // Got a request with a filled buffer.
            switch(pRequest->Verb)
            {
                case HttpVerbPOST:

                    TraceW(L"Got a POST request for %ws",
                           pRequest->CookedUrl.pFullUrl);              
                    
                    //Check if we need use authorization.
                    if(parmsP->authfn)
                    {
                        xmlrpc_env_init(&env);
                        if(pRequest->Headers.KnownHeaders[
                            HttpHeaderAuthorization].RawValueLength
                           < 6)
                        {
                            xmlrpc_env_set_fault(
                                &env, XMLRPC_REQUEST_REFUSED_ERROR, 
                                "Authorization header too short.");
                        }
                        else
                        {
                            //unencode the headers
                            if(_strnicmp(
                                "basic",
                                pRequest->Headers.KnownHeaders[
                                    HttpHeaderAuthorization].pRawValue,5)
                               !=0)
                            {
#ifndef  NDEBUG
                                PCHAR pTmp = (PCHAR)
                                    ALLOC_MEM(pRequest->Headers.KnownHeaders[
                                        HttpHeaderAuthorization
                                        ].RawValueLength + 1 );
                                if( pTmp ) {
                                    strncpy(pTmp,
                                            pRequest->Headers.KnownHeaders[
                                                HttpHeaderAuthorization
                                                ].pRawValue,
                                            pRequest->Headers.KnownHeaders[
                                                HttpHeaderAuthorization
                                                ].RawValueLength );
                                    pTmp[pRequest->Headers.KnownHeaders[
                                        HttpHeaderAuthorization
                                        ].RawValueLength] = 0;
                                    TraceA("Got HEADER [%s]",pTmp);
                                    FREE_MEM(pTmp);
                                }
#endif   /* #ifndef NDEBUG */
                                xmlrpc_env_set_fault(
                                    &env, XMLRPC_REQUEST_REFUSED_ERROR, 
                                    "Authorization header does not start "
                                    "with type 'basic'!");
                            }
                            else
                            {
                                xmlrpc_mem_block * decoded;
                                
                                decoded =
                                    xmlrpc_base64_decode(
                                        &env,
                                        pRequest->Headers.KnownHeaders[
                                            HttpHeaderAuthorization
                                            ].pRawValue+6,
                                        pRequest->Headers.KnownHeaders[
                                            HttpHeaderAuthorization
                                            ].RawValueLength-6);
                                if(!env.fault_occurred)
                                {
                                    char *pDecodedStr;
                                    char *pUser;
                                    char *pPass;
                                    char *pColon;
                                    
                                    pDecodedStr = (char*)
                                        malloc(decoded->_size+1);
                                    memcpy(pDecodedStr,
                                           decoded->_block,
                                           decoded->_size);
                                    pDecodedStr[decoded->_size]='\0';
                                    pUser = pPass = pDecodedStr;
                                    pColon=strchr(pDecodedStr,':');
                                    if(pColon)
                                    {
                                        *pColon='\0';
                                        pPass=pColon+1;
                                        //The authfn should set env to
                                        //fail if auth is denied.
                                        parmsP->authfn(&env,pUser,pPass);
                                    }
                                    else
                                    {
                                        xmlrpc_env_set_fault(
                                            &env,
                                            XMLRPC_REQUEST_REFUSED_ERROR, 
                                            "Decoded auth not of the correct "
                                            "format.");
                                    }
                                    free(pDecodedStr);
                                }
                                if(decoded)
                                    XMLRPC_MEMBLOCK_FREE(char, decoded);
                            }
                        }
                        if(env.fault_occurred)
                        {
                            //request basic authorization, as the user
                            //did not provide it.
                            xmlrpc_env_clean(&env);
                            TraceW(L"POST request did not provide valid "
                                   L"authorization header.");
                            result =
                                SendHttpResponseAuthRequired( hReqQueue,
                                                              pRequest);
                            break;
                        }
                        xmlrpc_env_clean(&env);
                    }
                    
                    //Check content type to make sure it is text/xml.
                    memcpy(szHeaderBuf,
                           pRequest->Headers.KnownHeaders[
                               HttpHeaderContentType
                               ].pRawValue,
                           pRequest->Headers.KnownHeaders[
                               HttpHeaderContentType
                               ].RawValueLength);
                    szHeaderBuf[pRequest->Headers.KnownHeaders[
                        HttpHeaderContentType
                        ].RawValueLength] = '\0';
                    if (_stricmp(szHeaderBuf,"text/xml")!=0)
                    {
                        //We handle only text/xml data.  Anything else
                        //is not valid.
                        TraceW(L"POST request had an unrecognized "
                               L"content-type: %s", szHeaderBuf);
                        result = SendHttpResponse(
                            hReqQueue, 
                            pRequest,
                            400,
                            "Bad Request",
                            NULL
                            );
                        break;
                    }

                    //Check content length to make sure it exists and
                    //is not too big.
                    memcpy(szHeaderBuf,
                           pRequest->Headers.KnownHeaders[
                               HttpHeaderContentLength
                               ].pRawValue,
                           pRequest->Headers.KnownHeaders[
                               HttpHeaderContentLength
                               ].RawValueLength);
                    szHeaderBuf[pRequest->Headers.KnownHeaders[
                        HttpHeaderContentLength
                        ].RawValueLength]='\0';
                    lContentLength = atol(szHeaderBuf);
                    if (lContentLength<=0)
                    {
                        //Make sure a content length was supplied.
                        TraceW(L"POST request did not include a "
                               L"content-length", szHeaderBuf);
                        result = SendHttpResponse(
                            hReqQueue, 
                            pRequest,
                            411,
                            "Length Required",
                            NULL
                            );
                        break;
                    }                       
                    if((size_t) lContentLength >
                       xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID))
                    {
                        //Content-length is too big for us to handle
                        TraceW(L"POST request content-length is too big "
                               L"for us to handle: %d bytes",
                               lContentLength);
                        result = SendHttpResponse(
                            hReqQueue, 
                            pRequest,
                            500,
                            "content-length too large",
                            NULL
                            );
                        break;
                    }

                    //our initial validations of POST, content-type,
                    //and content-length all check out.  Collect and
                    //pass the complete buffer to the XMLRPC-C library
                    
                    xmlrpc_env_init(&env);
                    processRPCCall(&env,hReqQueue, pRequest);
                    if (env.fault_occurred) 
                    {
                        //if we fail and it is anything other than a
                        //network error, we should return a failure
                        //response to the client.
                        if (env.fault_code != XMLRPC_NETWORK_ERROR)
                        {
                            if (env.fault_string)
                                result = SendHttpResponse(
                                    hReqQueue, 
                                    pRequest,
                                    500,
                                    env.fault_string,
                                    NULL
                                    );
                            else
                                result = SendHttpResponse(
                                    hReqQueue, 
                                    pRequest,
                                    500,
                                    "Unknown Error",
                                    NULL
                                    );
                        }
                    }
                    
                    xmlrpc_env_clean(&env);
                    break;

                default:
                    //We handle only POST data.  Anything else is not valid.
                    TraceW(L"Got an unrecognized Verb request for URI %ws",
                           pRequest->CookedUrl.pFullUrl);
            
                    result = SendHttpResponse(
                        hReqQueue, 
                        pRequest,
                        405,
                        "Method Not Allowed",
                        NULL
                        );
                    break;
            }
            if(result != NO_ERROR)
            {
                break;
            }

            // Reset the Request ID so that we pick up the next request.
            HTTP_SET_NULL_ID( &requestId );
        }
        else if(result == ERROR_MORE_DATA)
        {
            // The input buffer was too small to hold the request headers
            // We have to allocate more buffer & call the API again. 
            //
            // When we call the API again, we want to pick up the request
            // that just failed. This is done by passing a RequestID.
            // This RequestID is picked from the old buffer.
            requestId = pRequest->RequestId;

            // Free the old buffer and allocate a new one.
            RequestBufferLength = bytesRead;
            FREE_MEM( pRequestBuffer );
            pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength );

            if (pRequestBuffer == NULL)
            {
                result = ERROR_NOT_ENOUGH_MEMORY;
                break;
            }

            pRequest = (PHTTP_REQUEST)pRequestBuffer;

        }
        else if(ERROR_CONNECTION_INVALID == result && 
                !HTTP_IS_NULL_ID(&requestId))
        {
            // The TCP connection got torn down by the peer when we were
            // trying to pick up a request with more buffer. We'll just move
            // onto the next request.            
            HTTP_SET_NULL_ID( &requestId );
        }
        else
        {
            break;
        }

    } // for(;;)

    if(pRequestBuffer)
    {
        FREE_MEM( pRequestBuffer );
    }

    return result;
}