913 lines
26 KiB
C++
913 lines
26 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 2000.
|
||
|
//
|
||
|
// File: V A L I D A T E S O A P . C P P
|
||
|
//
|
||
|
// Contents: Implementation of SOAP request validation.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: spather 2000/11/8
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.h>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <httpext.h>
|
||
|
|
||
|
#include "hostp.h"
|
||
|
#include "ncxml.h"
|
||
|
#include "ncbase.h"
|
||
|
|
||
|
#include "ValidateSOAP.h"
|
||
|
|
||
|
const WCHAR CSZ_SOAP_NAMESPACE_URI[] =
|
||
|
L"http://schemas.xmlsoap.org/soap/envelope/";
|
||
|
const WCHAR CSZ_SOAP_ENCODING_STYLE_URI[] =
|
||
|
L"http://schemas.xmlsoap.org/soap/encoding/";
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateArguments(
|
||
|
IN IXMLDOMNode * pxdnAction,
|
||
|
IN IXMLDOMNodeList * pxdnlArgs,
|
||
|
IN IUPnPServiceDescriptionInfo * pServiceDescInfo)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BSTR bstrActionName = NULL;
|
||
|
|
||
|
hr = pxdnAction->get_baseName(&bstrActionName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BOOL fIsQueryStateVariable = FALSE;
|
||
|
DWORD cInArgs = 0;
|
||
|
BSTR * rgbstrNames = NULL;
|
||
|
BSTR * rgbstrTypes = NULL;
|
||
|
|
||
|
Assert(bstrActionName);
|
||
|
|
||
|
if (0 == lstrcmpW(bstrActionName, L"QueryStateVariable"))
|
||
|
{
|
||
|
fIsQueryStateVariable = TRUE;
|
||
|
cInArgs = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fIsQueryStateVariable = FALSE;
|
||
|
hr = pServiceDescInfo->GetInputArgumentNamesAndTypes(bstrActionName,
|
||
|
&cInArgs,
|
||
|
&rgbstrNames,
|
||
|
&rgbstrTypes);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
long listLength = 0;
|
||
|
|
||
|
hr = pxdnlArgs->get_length(&listLength);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if ((DWORD)listLength == cInArgs)
|
||
|
{
|
||
|
if (cInArgs > 0)
|
||
|
{
|
||
|
for (DWORD i = 0; i < cInArgs; i++)
|
||
|
{
|
||
|
IXMLDOMNode * pxdnArg = NULL;
|
||
|
|
||
|
hr = pxdnlArgs->get_item(i, &pxdnArg);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BSTR bstrArgName = NULL;
|
||
|
|
||
|
// Check that the name matches.
|
||
|
Assert(pxdnArg);
|
||
|
|
||
|
hr = pxdnArg->get_baseName(&bstrArgName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(bstrArgName);
|
||
|
|
||
|
if (fIsQueryStateVariable)
|
||
|
{
|
||
|
if (0 == lstrcmpiW(bstrArgName,
|
||
|
L"varName"))
|
||
|
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Invalid argument name",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (0 == lstrcmpiW(bstrArgName,
|
||
|
rgbstrNames[i]))
|
||
|
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Invalid argument name",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstrArgName);
|
||
|
}
|
||
|
pxdnArg->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Failed to get item",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Wrong number of input arguments in request",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Failed to get list length",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
if (FALSE == fIsQueryStateVariable)
|
||
|
{
|
||
|
if (cInArgs > 0)
|
||
|
{
|
||
|
for (DWORD i = 0; i < cInArgs; i++)
|
||
|
{
|
||
|
SysFreeString(rgbstrNames[i]);
|
||
|
rgbstrNames[i] = NULL;
|
||
|
SysFreeString(rgbstrTypes[i]);
|
||
|
rgbstrTypes[i] = NULL;
|
||
|
}
|
||
|
CoTaskMemFree(rgbstrNames);
|
||
|
rgbstrNames = NULL;
|
||
|
CoTaskMemFree(rgbstrTypes);
|
||
|
rgbstrTypes = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
SysFreeString(bstrActionName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Failed to get action name",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateArguments(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateActionName(
|
||
|
IN IXMLDOMNode * pxdnAction,
|
||
|
IN LPWSTR szSOAPActionHeader)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR szStrippedHeader = NULL;
|
||
|
DWORD cchSOAPActionHeader = 0;
|
||
|
LPWSTR szActionName = NULL;
|
||
|
|
||
|
cchSOAPActionHeader = lstrlenW(szSOAPActionHeader);
|
||
|
|
||
|
// Due to bugs in some SOAP implementations (specifically, the URT, not us)
|
||
|
// the SOAPActionHeader may or may not have double-quotes around it. We'll
|
||
|
// just remove them here if they are there (they should be, according to
|
||
|
// the SOAP spec).
|
||
|
|
||
|
if ((L'"' == szSOAPActionHeader[0]) &&
|
||
|
(L'"' == szSOAPActionHeader[cchSOAPActionHeader-1]))
|
||
|
{
|
||
|
// Modify the string in place - insert a NULL where the close
|
||
|
// quote is, and start the string 1 character from the beginning.
|
||
|
// Doing it this way, rather than copying the string saves us 1
|
||
|
// memory allocation.
|
||
|
|
||
|
szSOAPActionHeader[cchSOAPActionHeader-1] = UNICODE_NULL;
|
||
|
szStrippedHeader = szSOAPActionHeader+1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szStrippedHeader = szSOAPActionHeader;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Check that the action name matches the SOAPAction header.
|
||
|
// SOAPAction header is of the form servicetype#actionName.
|
||
|
|
||
|
szActionName = wcsstr(szStrippedHeader, L"#");
|
||
|
|
||
|
if (szActionName)
|
||
|
{
|
||
|
BSTR bstrActionName = NULL;
|
||
|
|
||
|
szActionName++; // Advance to the character after the "#"
|
||
|
|
||
|
hr = pxdnAction->get_baseName(&bstrActionName);
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
if (0 == lstrcmpiW(bstrActionName, szActionName))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateActionName(): "
|
||
|
"Action node name and SOAPAction header value match!");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateActionName(): "
|
||
|
"Action node name did not match SOAPAction header",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstrActionName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateActionName(): "
|
||
|
"Failed to get node name",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateActionName(): "
|
||
|
"SOAPActionHeader did not contain \"#\" character",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateActionName(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateBody(
|
||
|
IN IXMLDOMNode * pxdnBody,
|
||
|
IN IUPnPServiceDescriptionInfo * pServiceDescInfo,
|
||
|
IN LPWSTR szSOAPActionHeader)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
IXMLDOMNode * pxdnAction = NULL;
|
||
|
|
||
|
hr = pxdnBody->get_firstChild(&pxdnAction);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (pxdnAction)
|
||
|
{
|
||
|
hr = HrValidateActionName(pxdnAction, szSOAPActionHeader);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodeList * pxdnlArgs = NULL;
|
||
|
|
||
|
hr = pxdnAction->get_childNodes(&pxdnlArgs);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(pxdnlArgs);
|
||
|
|
||
|
hr = HrValidateArguments(pxdnAction,
|
||
|
pxdnlArgs,
|
||
|
pServiceDescInfo);
|
||
|
|
||
|
pxdnlArgs->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Finally, if all the above succeeded, check that the
|
||
|
// action element does not have a sibling (there should
|
||
|
// only be one child of the body element).
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNode * pxdnSibling = NULL;
|
||
|
|
||
|
hr = pxdnAction->get_nextSibling(&pxdnSibling);
|
||
|
|
||
|
if (S_FALSE == hr)
|
||
|
{
|
||
|
Assert(NULL == pxdnSibling);
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateBody(): "
|
||
|
"Body is valid!");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(pxdnSibling);
|
||
|
pxdnSibling->Release();
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateBody(): "
|
||
|
"Body element had more than one child",
|
||
|
hr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateBody(): "
|
||
|
"Failure trying to get next sibling",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pxdnAction->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateBody(): "
|
||
|
"Body element was empty",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateBody(): "
|
||
|
"Failed to get first child of body element",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateBody(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateSOAPHeader(
|
||
|
IN IXMLDOMNode * pxdnHeader)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
IXMLDOMNode * pxdnChild = NULL;
|
||
|
|
||
|
// A request may have headers as long as none of them have the
|
||
|
// "mustUnderstand" attribute set because we don't understand any
|
||
|
// headers.
|
||
|
|
||
|
hr = pxdnHeader->get_firstChild(&pxdnChild);
|
||
|
|
||
|
while (SUCCEEDED(hr) && pxdnChild)
|
||
|
{
|
||
|
IXMLDOMNode * pxdnNextSibling = NULL;
|
||
|
BSTR bstrMustUnderstand = NULL;
|
||
|
|
||
|
hr = HrGetTextValueFromAttribute(pxdnChild,
|
||
|
L"mustUnderstand",
|
||
|
&bstrMustUnderstand);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (NULL == bstrMustUnderstand)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateSOAPHeader(): "
|
||
|
"Found header without mustUnderstand attribute - ok!");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (0 == lstrcmpW(bstrMustUnderstand, L"0"))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateSOAPHeader(): "
|
||
|
"Found header with mustUnderstand "
|
||
|
"attribute == 0 - ok!");
|
||
|
}
|
||
|
else if (0 == lstrcmpW(bstrMustUnderstand, L"1"))
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPHeader(): "
|
||
|
"Found header with mustUnderstand attribute set",
|
||
|
hr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPHeader(): "
|
||
|
"Found header with invalid "
|
||
|
"mustUnderstand attribute value",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstrMustUnderstand);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceError("HrValidateSOAPError(): "
|
||
|
"Failed to get mustUnderstand attribute value",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pxdnChild->Release();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hr = pxdnChild->get_nextSibling(&pxdnNextSibling);
|
||
|
pxdnChild->Release();
|
||
|
pxdnChild = pxdnNextSibling;
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateSOAPHeader(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateSOAPStructure(
|
||
|
IN IXMLDOMNode * pxdnReqEnvelope,
|
||
|
IN IUPnPServiceDescriptionInfo * pServiceDescInfo,
|
||
|
IN LPWSTR szSOAPActionHeader)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (FIsThisTheNodeNameWithNamespace(pxdnReqEnvelope,
|
||
|
L"Envelope",
|
||
|
CSZ_SOAP_NAMESPACE_URI))
|
||
|
{
|
||
|
IXMLDOMNode * pxdnChild = NULL;
|
||
|
BOOL bFoundHeader = FALSE;
|
||
|
BOOL bFoundBody = FALSE;
|
||
|
|
||
|
|
||
|
hr = pxdnReqEnvelope->get_firstChild(&pxdnChild);
|
||
|
|
||
|
while (SUCCEEDED(hr) && pxdnChild)
|
||
|
{
|
||
|
IXMLDOMNode * pxdnNextSibling = NULL;
|
||
|
|
||
|
if (FIsThisTheNodeNameWithNamespace(pxdnChild,
|
||
|
L"Header",
|
||
|
CSZ_SOAP_NAMESPACE_URI))
|
||
|
{
|
||
|
if (FALSE == bFoundHeader)
|
||
|
{
|
||
|
bFoundHeader = TRUE;
|
||
|
hr = HrValidateSOAPHeader(pxdnChild);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPStructure(): "
|
||
|
"Duplicate header element found",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else if (FIsThisTheNodeNameWithNamespace(pxdnChild,
|
||
|
L"Body",
|
||
|
CSZ_SOAP_NAMESPACE_URI))
|
||
|
{
|
||
|
if (FALSE == bFoundBody)
|
||
|
{
|
||
|
bFoundBody = TRUE;
|
||
|
hr = HrValidateBody(pxdnChild,
|
||
|
pServiceDescInfo,
|
||
|
szSOAPActionHeader);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPStructure(): "
|
||
|
"Duplicate body element found",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPStructure(): "
|
||
|
"Unknown element found inside SOAP envelope",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pxdnChild->Release();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hr = pxdnChild->get_nextSibling(&pxdnNextSibling);
|
||
|
pxdnChild->Release();
|
||
|
pxdnChild = pxdnNextSibling;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (FALSE == bFoundBody)
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPStrucutre(): "
|
||
|
"Request was missing body element",
|
||
|
hr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateSOAPStructure(): "
|
||
|
"SOAP structure is valid!");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrValidateSOAPStructure(): "
|
||
|
"Root element is not a SOAP envelope",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateSOAPStructure(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrGetSOAPActionHeader(
|
||
|
IN LPEXTENSION_CONTROL_BLOCK pecb,
|
||
|
OUT LPWSTR * pszSOAPActionHeader)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR szSOAPActionHeader = NULL;
|
||
|
CHAR * szaBuffer = NULL;
|
||
|
DWORD cbBuffer = 0;
|
||
|
BOOL bReturn = FALSE;
|
||
|
|
||
|
// First we need to find the size of buffer we need to get all the HTTP
|
||
|
// headers.
|
||
|
|
||
|
bReturn = pecb->GetServerVariable(pecb->ConnID,
|
||
|
"ALL_RAW",
|
||
|
szaBuffer,
|
||
|
&cbBuffer);
|
||
|
|
||
|
if (FALSE == bReturn)
|
||
|
{
|
||
|
DWORD dwError = 0;
|
||
|
|
||
|
// Expect to be here - we passed in a null buffer and a zero size,
|
||
|
// in order to find what the real size should be.
|
||
|
|
||
|
dwError = GetLastError();
|
||
|
|
||
|
if (ERROR_INSUFFICIENT_BUFFER == dwError)
|
||
|
{
|
||
|
Assert(cbBuffer > 0);
|
||
|
|
||
|
szaBuffer = new CHAR[cbBuffer+1];
|
||
|
|
||
|
if (szaBuffer)
|
||
|
{
|
||
|
bReturn = pecb->GetServerVariable(pecb->ConnID,
|
||
|
"ALL_RAW",
|
||
|
szaBuffer,
|
||
|
&cbBuffer);
|
||
|
|
||
|
if (bReturn)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrGetSOAPActionHeader(): "
|
||
|
"All HTTP Headers:\n%s", szaBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrFromLastWin32Error();
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Failed to get all HTTP headers",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Failed to allocate buffer for all HTTP headers",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrFromLastWin32Error();
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Failed to get buffer size for all HTTP headers",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Should never be here.
|
||
|
|
||
|
Assert(FALSE);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CHAR * szaSOAPActionStart = NULL;
|
||
|
|
||
|
// Convert the buffer to uppercase.
|
||
|
for (DWORD i = 0; i < cbBuffer; i++)
|
||
|
{
|
||
|
szaBuffer[i] = (CHAR) toupper(szaBuffer[i]);
|
||
|
}
|
||
|
|
||
|
// Now we need find the SOAPAction header and get it's value.
|
||
|
|
||
|
szaSOAPActionStart = strstr(szaBuffer, "SOAPACTION:");
|
||
|
|
||
|
if (szaSOAPActionStart)
|
||
|
{
|
||
|
// Count the number of characters in the value of the header.
|
||
|
|
||
|
DWORD cbSOAPActionHeader = 0;
|
||
|
CHAR * szaSOAPActionValueStart = NULL;
|
||
|
CHAR * szaTemp = NULL;
|
||
|
|
||
|
szaSOAPActionValueStart = szaSOAPActionStart +
|
||
|
strlen("SOAPACTION:");
|
||
|
|
||
|
while (' ' == *szaSOAPActionValueStart || '\t' == *szaSOAPActionValueStart)
|
||
|
{
|
||
|
szaSOAPActionValueStart++;
|
||
|
}
|
||
|
|
||
|
szaTemp = szaSOAPActionValueStart;
|
||
|
|
||
|
while (('\0' != *szaTemp) &&
|
||
|
('\r' != *szaTemp) &&
|
||
|
('\n' != *szaTemp))
|
||
|
{
|
||
|
szaTemp++;
|
||
|
cbSOAPActionHeader++;
|
||
|
}
|
||
|
|
||
|
if (cbSOAPActionHeader > 0)
|
||
|
{
|
||
|
CHAR * szaSOAPActionHeader = NULL;
|
||
|
|
||
|
szaSOAPActionHeader = new CHAR[cbSOAPActionHeader + 1];
|
||
|
|
||
|
if (szaSOAPActionHeader)
|
||
|
{
|
||
|
strncpy(szaSOAPActionHeader,
|
||
|
szaSOAPActionValueStart,
|
||
|
cbSOAPActionHeader);
|
||
|
|
||
|
szaSOAPActionHeader[cbSOAPActionHeader] = '\0';
|
||
|
|
||
|
szSOAPActionHeader = WszFromSz(szaSOAPActionHeader);
|
||
|
|
||
|
if (szSOAPActionHeader)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidUDHISAPI,
|
||
|
"HrGetSOAPActionHeader(): "
|
||
|
"SOAPAction header value is %S",
|
||
|
szSOAPActionHeader);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Failed to allocate memory for "
|
||
|
"wide character SOAPAction header",
|
||
|
hr);
|
||
|
}
|
||
|
delete [] szaSOAPActionHeader;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Failed to allocate memory for SOAPAction header",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"SOAPAction header had no value",
|
||
|
hr);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = UPNP_E_MISSING_SOAP_ACTION;
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Could not find SOAPAction header",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
// Cleanup.
|
||
|
if (szaBuffer)
|
||
|
{
|
||
|
delete [] szaBuffer;
|
||
|
szaBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
// Copy the string to the out parameter if succeeded, otherwise
|
||
|
// clean it up.
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*pszSOAPActionHeader = szSOAPActionHeader;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Cleanup.
|
||
|
if (szSOAPActionHeader)
|
||
|
{
|
||
|
delete [] szSOAPActionHeader;
|
||
|
szSOAPActionHeader = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceError("HrGetSOAPActionHeader(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateContentType(
|
||
|
IN LPEXTENSION_CONTROL_BLOCK pecb)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL bReturn = FALSE;
|
||
|
const DWORD cdwBufSize = 512;
|
||
|
CHAR szaBuffer[cdwBufSize];
|
||
|
DWORD cbBuffer = cdwBufSize;
|
||
|
LPCSTR cszaExpectedContentType = "text/xml";
|
||
|
|
||
|
bReturn = pecb->GetServerVariable(pecb->ConnID,
|
||
|
"CONTENT_TYPE",
|
||
|
szaBuffer,
|
||
|
&cbBuffer);
|
||
|
|
||
|
if (bReturn)
|
||
|
{
|
||
|
Assert(cbBuffer <= cdwBufSize);
|
||
|
|
||
|
if (0 == strncmp(szaBuffer,
|
||
|
cszaExpectedContentType,
|
||
|
strlen(cszaExpectedContentType)))
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateContentType(): "
|
||
|
"Valid content type %s",
|
||
|
szaBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_CONTENT_TYPE;
|
||
|
TraceTag(ttidValidate,
|
||
|
"HrValidateContentType(): "
|
||
|
"Invalid content type %s",
|
||
|
szaBuffer);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HrFromLastWin32Error();
|
||
|
TraceError("HrValidateContentType(): "
|
||
|
"Failed to get content type",
|
||
|
hr);
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateContentType(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrValidateSOAPRequest
|
||
|
//
|
||
|
// Purpose: Validates the structure of a SOAP request.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pxdnReqEnvelope [in] The XML DOM Node for the SOAP envelope element
|
||
|
// pecb [in] The extension control block for the request
|
||
|
// pServiceDescInfo [in] The service description info object for the
|
||
|
// service at which the request is targeted
|
||
|
//
|
||
|
// Returns:
|
||
|
// If the function succeeds, the return value is S_OK. Otherwise, the
|
||
|
// function returns one of the COM error codes defined in WinError.h.
|
||
|
//
|
||
|
// Author: spather 2000/11/8
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
|
||
|
HRESULT
|
||
|
HrValidateSOAPRequest(
|
||
|
IN IXMLDOMNode * pxdnReqEnvelope,
|
||
|
IN LPEXTENSION_CONTROL_BLOCK pecb,
|
||
|
IN IUPnPServiceDescriptionInfo * pServiceDescInfo)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
Assert(pxdnReqEnvelope);
|
||
|
Assert(pecb);
|
||
|
Assert(pServiceDescInfo);
|
||
|
|
||
|
hr = HrValidateContentType(pecb);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LPWSTR szSOAPActionHeader = NULL;
|
||
|
|
||
|
hr = HrGetSOAPActionHeader(pecb, &szSOAPActionHeader);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
Assert(szSOAPActionHeader);
|
||
|
|
||
|
hr = HrValidateSOAPStructure(pxdnReqEnvelope,
|
||
|
pServiceDescInfo,
|
||
|
szSOAPActionHeader);
|
||
|
|
||
|
delete [] szSOAPActionHeader;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (E_FAIL == hr)
|
||
|
{
|
||
|
hr = UPNP_E_BAD_REQUEST;
|
||
|
}
|
||
|
|
||
|
TraceError("HrValidateSOAPRequest(): "
|
||
|
"Exiting",
|
||
|
hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|