windows-nt/Source/XPSP1/NT/net/upnp/host/udhisapi/evtrqst.cpp

1038 lines
28 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: E V T R Q S T . C P P
//
// Contents: Handles eventing-related requests for the UPnP Device Host
//
// Notes:
//
// Author: danielwe 11 Aug 2000
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include <httpext.h>
#include <wininet.h>
#include <winsock.h>
#include "udhiutil.h"
#include "evtrqst.h"
#include "hostp.h"
#include "ncbase.h"
#include "ncstring.h"
static const DWORD c_csecDefaultTimeout = 6 * 60 * 60; // 6 hours
DWORD WINAPI
DwHandleEventRequest(
LPVOID lpParameter)
{
DWORD hseStatus = HSE_STATUS_SUCCESS;
LPEXTENSION_CONTROL_BLOCK pecb = NULL;
HRESULT hr = S_OK;
pecb = (LPEXTENSION_CONTROL_BLOCK) lpParameter;
AssertSz(pecb, "NULL Extension Control Block!");
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
if (pecb->lpszMethod)
{
TraceTag(ttidIsapiCtl, "Got method %s", pecb->lpszMethod);
if (!lstrcmpiA(pecb->lpszMethod, "SUBSCRIBE"))
{
hseStatus = DwHandleSubscribeMethod(pecb);
}
else if (!lstrcmpiA(pecb->lpszMethod, "UNSUBSCRIBE"))
{
hseStatus = DwHandleUnSubscribeMethod(pecb);
}
else
{
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
hseStatus = HSE_STATUS_ERROR;
}
}
if (hseStatus == HSE_STATUS_ERROR)
{
SendSimpleResponse(pecb, pecb->dwHttpStatusCode);
}
CoUninitialize();
}
else
{
SendSimpleResponse(pecb, HTTP_STATUS_SERVER_ERROR);
}
if(hseStatus != HSE_STATUS_ERROR)
{
BOOL fKeepConn = FALSE;
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_IS_KEEP_CONN,
&fKeepConn,
NULL,
NULL);
if(fKeepConn)
hseStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
else
hseStatus = HSE_STATUS_SUCCESS;
}
return hseStatus;
}
//+---------------------------------------------------------------------------
//
// Function: FIsHeaderPresent
//
// Purpose: Tests to see if a particular header is present on the given
// HTTP request
//
// Arguments:
// pecb [in] Extension control block
// szaHeader [in] Header name to test
//
// Returns: TRUE if header was present, FALSE if not or if error
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
BOOL FIsHeaderPresent(LPEXTENSION_CONTROL_BLOCK pecb, LPCSTR szaHeader)
{
LPSTR szaResult;
BOOL fRet = FALSE;
// Ensure SID header is NOT present
if (DwQueryHeader(pecb, szaHeader, &szaResult) == ERROR_SUCCESS)
{
delete [] szaResult;
fRet = TRUE;
}
return fRet;
}
//+---------------------------------------------------------------------------
//
// Function: DwParseTime
//
// Purpose: Parses the Timeout header of a SUBSCRIBE request
//
// Arguments:
// szaTime [in] Timeout value in the format defined by RFC2518
//
// Returns: Timeout value in SECONDS
//
// Author: danielwe 13 Oct 1999
//
// Notes:
//
DWORD DwParseTime(LPCSTR szaTime)
{
CHAR szaDigits[64];
const CHAR c_szaTimeout[] = "Second-";
const INT c_cchTimeout = lstrlenA(c_szaTimeout);
DWORD iDigit = 0;
if (szaTime && (lstrlenA(szaTime) > c_cchTimeout))
{
if (!_strnicmp(szaTime, c_szaTimeout, c_cchTimeout))
{
DWORD dwDigits;
// Ok we know we have at least "Timeout-x" now
szaTime += c_cchTimeout;
*szaDigits = 0;
while (isdigit(*szaTime) && (iDigit < sizeof(szaDigits)))
{
// Copy the digits into the buffer
szaDigits[iDigit++] = *szaTime++;
}
dwDigits = strtoul(szaDigits, NULL, 10);
if (dwDigits)
{
return dwDigits;
}
else
{
return c_csecDefaultTimeout;
}
}
}
TraceTag(ttidEvents, "DwParseTime: Invalid timeout header %s. Returning "
"default timeout of %d", szaTime ? szaTime : "<NULL>",
c_csecDefaultTimeout);
return c_csecDefaultTimeout;
}
//+---------------------------------------------------------------------------
//
// Function: DwGetTimeout
//
// Purpose: Queries the timeout header for a SUBSCRIBE request and
// parses it
//
// Arguments:
// pecb [in] Extension control block
//
// Returns: Timeout queried, in seconds. If no timeout header was present
// or it was invalid, a default timeout is returned.
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwGetTimeout(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD csecTimeout;
LPSTR szaTimeout;
if (DwQueryHeader(pecb, "HTTP_TIMEOUT", &szaTimeout) == ERROR_SUCCESS)
{
csecTimeout = DwParseTime(szaTimeout);
TraceTag(ttidIsapiEvt, "DwGetTimeout: Queried "
"timeout header = %d", csecTimeout);
delete [] szaTimeout;
}
else
{
// Default to reasonable amount
csecTimeout = c_csecDefaultTimeout;
TraceTag(ttidIsapiEvt, "DwGetTimeout: No Timeout header found. Using"
"default timeout: %d", csecTimeout);
}
return csecTimeout;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetEventingManager
//
// Purpose: Given the query string passed to the ISAPI DLL, returns
// the eventing manager object associated with that query
//
// Arguments:
// szaQueryString [in] Query string from event subscription request
// ppuem [out] Returns the eventing manager object
//
// Returns: S_OK if successful, E_OUTOFMEMORY, or E_INVALIDARG if the
// query string was malformed. Also will return an error if
// the corresponding eventing manager object could not be found.
//
// Author: danielwe 2000/08/16
//
// Notes:
//
HRESULT HrGetEventingManager(LPSTR szaQueryString,
IUPnPEventingManager **ppuem)
{
HRESULT hr = S_OK;
LPSTR szaUdn;
LPSTR szaServiceId;
LPWSTR szUdn = NULL;
LPWSTR szServiceId = NULL;
const CHAR c_szPrefix[] = "event=";
Assert(szaQueryString);
szaQueryString = strstr(szaQueryString, c_szPrefix);
if (szaQueryString)
{
szaQueryString += lstrlenA(c_szPrefix);
TraceTag(ttidIsapiEvt, "HrGetEventingManager: Asking registrar for "
"the eventing manager with query string: %s", szaQueryString);
}
else
{
hr = E_INVALIDARG;
TraceTag(ttidIsapiEvt, "HrGetEventingManager: Invalid query"
" string: %s", szaQueryString);
goto cleanup;
}
szaUdn = strtok(szaQueryString, "+");
if (szaUdn)
{
szUdn = WszFromSz(szaUdn);
if (szUdn)
{
szaServiceId = strtok(NULL, "+");
if (szaServiceId)
{
szServiceId = WszFromSz(szaServiceId);
if (szServiceId)
{
IUPnPRegistrarLookup * purl = NULL;
hr = CoCreateInstance(CLSID_UPnPRegistrar, NULL,
CLSCTX_INPROC_SERVER,
IID_IUPnPRegistrarLookup,
(LPVOID *)&purl);
if (SUCCEEDED(hr))
{
hr = purl->GetEventingManager(szUdn, szServiceId,
ppuem);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_INVALIDARG;
TraceTag(ttidIsapiEvt, "HrGetEventingManager: Invalid query"
" string: %s", szaQueryString);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_INVALIDARG;
TraceTag(ttidIsapiEvt, "HrGetEventingManager: Invalid query"
" string: %s", szaQueryString);
}
cleanup:
delete [] szUdn;
delete [] szServiceId;
TraceError("HrGetEventingManager", hr);
return hr;
}
static const DWORD c_dwUPnPMajorVersion = 1;
static const DWORD c_dwUPnPMinorVersion = 0;
static const DWORD c_dwHostMajorVersion = 1;
static const DWORD c_dwHostMinorVersion = 0;
//+---------------------------------------------------------------------------
//
// Function: DwSendSubscribeResponse
//
// Purpose: Sends the response to a SUBSCRIBE request
//
// Arguments:
// pecb [in] Extension control block
// csecTimeout [in] Subscription timeout in seconds
// szaSid [in] SID of subscription
//
// Returns: HSE_STATUS_SUCCESS or HSE_STATUS_ERROR
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwSendSubscribeResponse(LPEXTENSION_CONTROL_BLOCK pecb,
DWORD csecTimeout, LPCSTR szaSid)
{
DWORD dwReturn = HSE_STATUS_SUCCESS;
CHAR szaTimeout[256];
CHAR szaSidHeader[256];
OSVERSIONINFO osvi = {0};
LPSTR szaBuf;
DWORD cchBuf;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
BOOL fKeepConn = FALSE;
// Maximum size of SID value
static const DWORD c_cchMaxSid = 47;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
wsprintfA(szaTimeout, "Timeout: Second-%d\r\n", csecTimeout);
AssertSz(lstrlenA(szaSid) <= c_cchMaxSid, "Invalid SID size!");
wsprintfA(szaSidHeader, "SID: %s\r\n", szaSid);
cchBuf = lstrlenA(szaTimeout) +
lstrlenA(szaSidHeader) +
2 + // CRLF (terminating)
1; // Terminating NULL
szaBuf = new CHAR[cchBuf];
if (!szaBuf)
{
dwReturn = HSE_STATUS_ERROR;
pecb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
}
else
{
lstrcpyA(szaBuf, szaTimeout);
lstrcatA(szaBuf, szaSidHeader);
lstrcatA(szaBuf, "\r\n");
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_IS_KEEP_CONN,
&fKeepConn,
NULL,
NULL);
HeaderExInfo.pszStatus = NULL;
HeaderExInfo.pszHeader = szaBuf;
HeaderExInfo.cchStatus = 0 ;
HeaderExInfo.cchHeader = cchBuf;
HeaderExInfo.fKeepConn = fKeepConn;
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&HeaderExInfo,
NULL,
NULL);
delete [] szaBuf;
}
return dwReturn;
}
const CHAR c_szaUrlPrefix[] = "<http://";
//+--------------------------------------------------------------------------
// Function: strcasestr
//
// Purpose: a case-insensitive variant of strstr
//
// Arguments: szBuff [in] the string to search
// szText[in] the text to search for
//
// Returns: a pointer to the first match in szBuff, or NULL if no match
//
LPSTR strcasestr(LPSTR szBuff, const LPSTR szText)
{
const LPSTR szText1 = (const LPSTR)(szText+1);
char firstc = *szText;
if (firstc)
{
if (isupper(firstc))
firstc = (char)tolower(firstc);
int len = strlen(szText1);
do {
// search for a match of the first char
char buffc;
for (;;)
{
buffc = *szBuff++;
if (buffc == 0) return NULL; // failure
if ((buffc == firstc) || (isupper(buffc) && (tolower(buffc) == firstc)))
break; // matched!
}
// we matched the first char. Now check the rest. If we fail,
// loop around again; if we succeed, stop looping
} while (_strnicmp(szBuff, szText1, len) != 0);
// go back one as we matched (szText+1)
--szBuff;
}
return szBuff;
}
//+---------------------------------------------------------------------------
//
// Function: FParseCallbackUrl
//
// Purpose: Given the Callback URL header value, determines the list of
// http:// URLs.
//
// Arguments:
// szCallbackUrl [in] URL to process (comes from Callback: header)
// pcszOut [out] Number of URLs parsed
// pszOut [out] Array of valid callback URLs.
//
// Returns: TRUE if URL format is valid, FALSE if not or if out of
// memory.
//
// Author: danielwe 13 Oct 1999
//
// Notes: Caller must free the prgszOut array with delete []
//
BOOL FParseCallbackUrl(LPCSTR szaCallbackUrl, DWORD *pcszOut,
LPWSTR **prgszOut)
{
CONST INT c_cchPrefix = lstrlenA(c_szaUrlPrefix);
LPSTR szaTemp;
LPSTR pchPos;
LPSTR szaOrig = NULL;
BOOL fResult = FALSE;
LPWSTR * rgszOut = NULL;
DWORD isz = 0;
// NOTE: This function will return http:// as a URL.. Corner case, but
// not catastrophic
Assert(szaCallbackUrl);
Assert(prgszOut);
Assert(pcszOut);
*prgszOut = NULL;
*pcszOut = 0;
// Copy the original URL so we can lowercase
//
szaTemp = SzaDupSza(szaCallbackUrl);
if (!szaTemp)
{
TraceError("FParseCallbackUrl", E_OUTOFMEMORY);
return FALSE;
}
szaOrig = szaTemp;
// Count the approximate number of URLs so we know how big of an array to
// allocate. We do this by counting the number of open angle brackets we
// see (<).
DWORD cUrl = 0;
pchPos = szaTemp;
while (*pchPos)
{
if (*pchPos == '<')
{
cUrl++;
}
pchPos++;
}
rgszOut = new LPWSTR[cUrl];
if (rgszOut)
{
// Look for <http://
//
pchPos = strcasestr(szaTemp, (const LPSTR)c_szaUrlPrefix);
while (pchPos)
{
// Look for the closing '>'
szaTemp = pchPos + c_cchPrefix;
while (*szaTemp && *szaTemp != '>')
{
szaTemp++;
}
pchPos++;
if (*szaTemp)
{
DWORD_PTR cchOut;
CHAR szaUrl[INTERNET_MAX_PATH_LENGTH];
Assert(*szaTemp == '>');
// copy in the URL
//
cchOut = min(szaTemp - pchPos + 1, INTERNET_MAX_PATH_LENGTH - 1);
lstrcpynA(szaUrl, pchPos, (int)cchOut);
szaUrl[cchOut] = 0;
rgszOut[isz] = WszFromSz(szaUrl);
if (rgszOut[isz++])
{
fResult = TRUE;
}
else
{
fResult = FALSE;
break;
}
}
pchPos = szaTemp;
pchPos = strstr(pchPos, c_szaUrlPrefix);
}
}
if (fResult)
{
*prgszOut = rgszOut;
*pcszOut = isz;
}
else
{
DWORD iszIter;
for (iszIter = 0; iszIter < isz; iszIter++)
{
delete [] rgszOut[iszIter];
}
delete [] rgszOut;
}
delete [] szaOrig;
TraceResult("FParseCallbackUrl", fResult);
return fResult;
}
//+---------------------------------------------------------------------------
//
// Function: DwHandleSubscribeRequest
//
// Purpose: Handles the processing of a SUBSCRIBE request
//
// Arguments:
// pecb [in] Extension control block
//
// Returns: HSE_STATUS_SUCCESS or HSE_STATUS_ERROR
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwHandleSubscribeRequest(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD dwReturn;
DWORD csecTimeout;
HRESULT hr = S_OK;
LPSTR szaTimeout = NULL;
LPWSTR szCallbackUrl = NULL;
LPWSTR szSid = NULL;
LPSTR szaSid = NULL;
LPSTR szaAddr = NULL;
LPSTR szaCallback = NULL;
LPWSTR * rgszUrl;
DWORD cszUrl = 0;
DWORD dwIpAddr = 0;
IUPnPEventingManager * puem = NULL;
pecb->dwHttpStatusCode = HTTP_STATUS_OK;
dwReturn = DwQueryHeader(pecb, "LOCAL_ADDR", &szaAddr);
if (ERROR_SUCCESS == dwReturn)
{
dwIpAddr = inet_addr(szaAddr);
delete [] szaAddr;
}
else
{
TraceError("Could not obtain remote IP address!", E_FAIL);
}
dwReturn = DwQueryHeader(pecb, "HTTP_CALLBACK", &szaCallback);
if (dwReturn == ERROR_SUCCESS)
{
AssertSz(szaCallback, "Callback string must not be NULL!");
// Parse the callback URL given us. It will be of the format:
// <[url]><[url]> but we only care about the first URL in the list
// That's what we will have after this function returns. If the format
// of the callback header was invalid, the return will be FALSE
//
if (!FParseCallbackUrl(szaCallback, &cszUrl, &rgszUrl))
{
TraceTag(ttidIsapiEvt, "Invalid callback URL: '%s'", szaCallback);
// Callback URL is not valid
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
}
else
{
// Valid callback URL. Continue
csecTimeout = DwGetTimeout(pecb);
// Ensure SID header is NOT present
if (FIsHeaderPresent(pecb, "HTTP_SID"))
{
TraceTag(ttidIsapiEvt, "SID header was present on a subscribe!");
// Not supposed to have this header. Return error!
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
dwReturn = HSE_STATUS_ERROR;
}
else
{
dwReturn = ERROR_SUCCESS;
hr = HrGetEventingManager(pecb->lpszQueryString, &puem);
if (SUCCEEDED(hr))
{
Assert(rgszUrl);
Assert(cszUrl);
hr = puem->AddSubscriber(cszUrl,
const_cast<LPCWSTR *>(rgszUrl),
dwIpAddr,
&csecTimeout, &szSid);
if (SUCCEEDED(hr))
{
// Covert the SID returned from the EM object back to
// an ANSI string for the response
//
szaSid = SzFromWsz(szSid);
if (!szaSid)
{
pecb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
dwReturn = HSE_STATUS_ERROR;
goto cleanup;
}
dwReturn = DwSendSubscribeResponse(pecb, csecTimeout,
szaSid);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
TraceTag(ttidIsapiEvt, "Eventing manager says event "
"source did not exist!");
pecb->dwHttpStatusCode = HTTP_STATUS_NOT_FOUND;
dwReturn = HSE_STATUS_ERROR;
// So we don't overwrite this error
hr = S_OK;
}
}
}
DWORD iszUrl;
for (iszUrl = 0; iszUrl < cszUrl; iszUrl++)
{
delete [] rgszUrl[iszUrl];
}
delete [] rgszUrl;
}
}
else
{
TraceTag(ttidIsapiEvt, "DwHandleSubscribeRequest: Callback URL was "
"not present!");
// Callback URL is not present
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
}
cleanup:
if (FAILED(hr))
{
TraceError("DwHandleSubscribeRequest", hr);
pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
dwReturn = HSE_STATUS_ERROR;
}
TraceTag(ttidIsapiEvt, "DwHandleSubscribeRequest returning %d", dwReturn);
delete [] szaTimeout;
delete [] szaSid;
delete [] szCallbackUrl;
CoTaskMemFree(szSid);
delete [] szaCallback;
ReleaseObj(puem);
return dwReturn;
}
//+---------------------------------------------------------------------------
//
// Function: DwHandleResubscribeRequest
//
// Purpose: Handles the processing of a re-SUBSCRIBE request
//
// Arguments:
// pecb [in] Extension control block
//
// Returns: HSE_STATUS_SUCCESS or HSE_STATUS_ERROR
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwHandleResubscribeRequest(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD dwReturn = HSE_STATUS_SUCCESS;
LPSTR szaSid = NULL;
LPWSTR szSid = NULL;
HRESULT hr = S_OK;
IUPnPEventingManager * puem = NULL;
pecb->dwHttpStatusCode = HTTP_STATUS_OK;
// Ensure SID header is NOT present
dwReturn = DwQueryHeader(pecb, "HTTP_SID", &szaSid);
if (dwReturn == ERROR_SUCCESS)
{
AssertSz(!FIsHeaderPresent(pecb, "HTTP_NT"), "NT header is "
"not supposed to be here!");
if (FIsHeaderPresent(pecb, "HTTP_CALLBACK"))
{
TraceTag(ttidIsapiEvt, "Callback header was present on a "
"re-subscribe!");
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
dwReturn = HSE_STATUS_ERROR;
}
else
{
DWORD csecTimeout;
csecTimeout = DwGetTimeout(pecb);
hr = HrGetEventingManager(pecb->lpszQueryString, &puem);
if (SUCCEEDED(hr))
{
// Convert the SID from the request to a UNICODE string for
// the EM object
//
szSid = WszFromSz(szaSid);
if (!szSid)
{
pecb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
dwReturn = HSE_STATUS_ERROR;
goto cleanup;
}
hr = puem->RenewSubscriber(&csecTimeout, szSid);
if (SUCCEEDED(hr))
{
dwReturn = DwSendSubscribeResponse(pecb, csecTimeout,
szaSid);
}
else if (HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION) == hr)
{
TraceTag(ttidIsapiEvt, "Eventing manager says subscriber"
" did not exist!");
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
// So we don't overwrite this error
hr = S_OK;
}
}
}
}
else
{
TraceTag(ttidIsapiEvt, "SID header was NOT present on a re-subscribe!");
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
}
cleanup:
if (FAILED(hr))
{
TraceError("DwHandleResubscribeRequest", hr);
pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
dwReturn = HSE_STATUS_ERROR;
}
TraceTag(ttidIsapiEvt, "DwHandleResubscribeRequest: returning %d",
dwReturn);
delete [] szaSid;
delete [] szSid;
ReleaseObj(puem);
return dwReturn;
}
//+---------------------------------------------------------------------------
//
// Function: DwHandleSubscribeMethod
//
// Purpose: Handles the processing of a request with the SUBSCRIBE
// method
//
// Arguments:
// pecb [in] Extension control block
//
// Returns: HSE_STATUS_SUCCESS or HSE_STATUS_ERROR
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwHandleSubscribeMethod(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD dwReturn;
LPSTR szaNt;
dwReturn = DwQueryHeader(pecb, "HTTP_NT", &szaNt);
if (dwReturn == ERROR_SUCCESS)
{
TraceTag(ttidIsapiEvt, "Queried NT header was '%s'", szaNt);
if (!lstrcmpiA("upnp:event", szaNt))
{
// NT header was present and is correctly "upnp:event". Assume
// that it is a subscribe request
dwReturn = DwHandleSubscribeRequest(pecb);
}
else
{
TraceTag(ttidIsapiEvt, "NT header was not \"upnp:event\" (%s)",
szaNt);
// Whoa! Not "upnp:event". Send 412 Precondition failed
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
}
delete [] szaNt;
}
else if (dwReturn == ERROR_INVALID_INDEX)
{
// NT header was not present. Assume it's now a re-subscribe request
dwReturn = DwHandleResubscribeRequest(pecb);
}
else
{
dwReturn = HSE_STATUS_ERROR;
pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
}
return dwReturn;
}
//+---------------------------------------------------------------------------
//
// Function: DwHandleUnSubscribeMethod
//
// Purpose: Handles the processing of an UNSUBSCRIBE request
//
// Arguments:
// pecb [in] Extension control block
//
// Returns: HSE_STATUS_SUCCESS or HSE_STATUS_ERROR
//
// Author: danielwe 14 Aug 2000
//
// Notes:
//
DWORD DwHandleUnSubscribeMethod(LPEXTENSION_CONTROL_BLOCK pecb)
{
DWORD dwReturn = HSE_STATUS_SUCCESS;
LPSTR szaSid = NULL;
HRESULT hr = S_OK;
LPWSTR szSid = NULL;
pecb->dwHttpStatusCode = HTTP_STATUS_OK;
// Ensure SID header is NOT present
dwReturn = DwQueryHeader(pecb, "HTTP_SID", &szaSid);
if (dwReturn == ERROR_SUCCESS)
{
if (FIsHeaderPresent(pecb, "HTTP_CALLBACK") ||
FIsHeaderPresent(pecb, "HTTP_NT"))
{
TraceTag(ttidIsapiEvt, "Callback or NT header was present on an "
"unsubscribe!");
pecb->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
dwReturn = HSE_STATUS_ERROR;
}
else
{
IUPnPEventingManager * puem = NULL;
hr = HrGetEventingManager(pecb->lpszQueryString, &puem);
if (SUCCEEDED(hr))
{
szSid = WszFromSz(szaSid);
if (!szSid)
{
pecb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
dwReturn = HSE_STATUS_ERROR;
goto cleanup;
}
hr = puem->RemoveSubscriber(szSid);
if (SUCCEEDED(hr))
{
SendSimpleResponse(pecb, HTTP_STATUS_OK);
}
// No explicit response headers needed because UNSUBSCRIBE
// doesn't have any headers associated with its response
ReleaseObj(puem);
}
}
}
else
{
TraceTag(ttidIsapiEvt, "SID header was not present on an UNSUBSCRIBE");
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
dwReturn = HSE_STATUS_ERROR;
}
cleanup:
if (FAILED(hr))
{
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
pecb->dwHttpStatusCode = HTTP_STATUS_PRECOND_FAILED;
}
else
{
pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
}
TraceError("DwHandleUnSubscribeMethod", hr);
dwReturn = HSE_STATUS_ERROR;
}
TraceTag(ttidIsapiEvt, "DwHandleUnSubscribeMethod: returning %d",
dwReturn);
delete [] szSid;
delete [] szaSid;
return dwReturn;
}