windows-nt/Source/XPSP1/NT/net/upnp/host/udhisapi/descrqst.cpp
2020-09-26 16:20:57 +08:00

387 lines
10 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000.
//
// File: D E S C R Q S T . C P P
//
// Contents: Implementation of description request processing for the
// UPnP Device Host ISAPI Extension
//
// Notes:
//
// Author: spather 2000/08/31
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include <wininet.h>
#include "descrqst.h"
#include "udhiutil.h"
#include "hostp.h"
#include "uhcommon.h"
#include "ncstring.h"
//+---------------------------------------------------------------------------
//
// Function: HrValidateDescriptionMethod
//
// Purpose: Validates that the HTTP verb used is valid for this
// type of request.
//
// Arguments:
// pszaMethod [in] The HTTP verb
//
// Returns:
// If the method is valid, the return value is S_OK. If the method is
// not valid, the function returns one of the COM error codes defined
// in WinError.h.
//
// Author: spather 2000/09/21
//
// Notes:
//
HRESULT
HrValidateDescriptionMethod(
IN LPSTR pszaMethod)
{
HRESULT hr = S_OK;
AssertSz(pszaMethod,
"HrValidateDescriptionMethod(): NULL Method passed");
if (0 != lstrcmpiA(pszaMethod, "GET"))
{
hr = E_FAIL;
}
TraceError("HrValidateDescriptionMethod(): Exiting",
hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrParseDescriptionQueryString
//
// Purpose: Parses a description request's query string and extracts
// the content GUID from it.
//
// Arguments:
// pszaQueryString [in] The query string to parse
// rguidContent [out] Points to a GUID structure that will be
// initialized with the content GUID as parsed
//
// 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/09/14
//
// Notes:
//
HRESULT
HrParseDescriptionQueryString(
IN LPSTR pszaQueryString,
OUT GUID & rguidContent)
{
HRESULT hr = S_OK;
LPWSTR szQueryString;
Assert(pszaQueryString);
szQueryString = WszFromSz(pszaQueryString);
if (szQueryString)
{
hr = HrContentURLToGUID(szQueryString, rguidContent);
delete [] szQueryString;
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrParseDescriptionQueryString(): "
"Unable to allocate memory for content URL",
hr);
}
TraceError("HrParseDescriptionQueryString(): "
"Exiting",
hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrReturnContent
//
// Purpose: Retrieves content from a content source and sends it back
// to the originator of a description request
//
// Arguments:
// pecb [in] The extension control block for the description
// request
// pudcs [in] The dynamic content source
// rguidContent [in] The GUID identifying the content being requested.
//
// 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/09/14
//
// Notes:
//
HRESULT
HrReturnContent(
LPEXTENSION_CONTROL_BLOCK pecb,
IUPnPDynamicContentSource * pudcs,
REFGUID rguidContent)
{
HRESULT hr = S_OK;
LONG nHeaders = 0;
LPWSTR * rgszHeaders = NULL;
LONG nBytes = 0;
BYTE * rgBytes = NULL;
hr = pudcs->GetContent(rguidContent,
&nHeaders,
&rgszHeaders,
&nBytes,
&rgBytes);
if (SUCCEEDED(hr))
{
DWORD cchHeaders = 0;
LPSTR pszaHeaders = NULL;
Assert(rgszHeaders);
Assert(rgBytes);
// Need to merge the headers into a single ASCII string. Each
// Headers will be delimited by \r\n pairs and the last header
// will be followed by 2 \r\n pairs.
for (LONG i = 0; i < nHeaders; i++)
{
cchHeaders += lstrlenW(rgszHeaders[i]);
cchHeaders += 2; // For the "\r\n" pair
}
cchHeaders += 2; // For the final "\r\n"
pszaHeaders = new CHAR[cchHeaders+1];
if (pszaHeaders)
{
LPSTR pszaNextHeader = pszaHeaders;
for (LONG i = 0; i < nHeaders; i++)
{
DWORD cchCurHeader;
cchCurHeader = lstrlenW(rgszHeaders[i]);
wsprintfA(pszaNextHeader,
"%S\r\n",
rgszHeaders[i]);
pszaNextHeader += cchCurHeader+2; // +2 for \r\n
}
lstrcpyA(pszaNextHeader,
"\r\n");
if (bSendResponseToClient(pecb,
"200 OK",
cchHeaders,
pszaHeaders,
nBytes,
(LPCSTR) rgBytes))
{
pecb->dwHttpStatusCode = HTTP_STATUS_OK;
TraceTag(ttidUDHISAPI,
"HrReturnContent(): "
"Successfully sent response to client");
}
delete [] pszaHeaders;
pszaHeaders = NULL;
}
else
{
hr = E_OUTOFMEMORY;
TraceError("HrReturnContent(): "
"Failed to allocate memory for headers",
hr);
}
// Free memory returned from GetContent().
for (LONG i = 0; i < nHeaders; i++)
{
CoTaskMemFree(rgszHeaders[i]);
rgszHeaders[i] = NULL;
}
CoTaskMemFree(rgszHeaders);
rgszHeaders = NULL;
CoTaskMemFree(rgBytes);
rgBytes = NULL;
}
else
{
TraceError("HrReturnContent(): "
"Failed to get content",
hr);
}
TraceError("HrReturnContent(): "
"Exiting",
hr);
return hr;
}
DWORD WINAPI
DwHandleContentRequest(
LPVOID lpParameter)
{
LPEXTENSION_CONTROL_BLOCK pecb = NULL;
DWORD dwStatus = HSE_STATUS_SUCCESS ;
HCONN ConnID;
HRESULT hr = S_OK;
GUID guidContent;
BOOL fKeepConn = FALSE;
pecb = (LPEXTENSION_CONTROL_BLOCK) lpParameter;
AssertSz(pecb,
"DwHandleContentRequest(): "
"NULL extension control block");
pecb->ServerSupportFunction(
pecb->ConnID,
HSE_REQ_IS_KEEP_CONN,
&fKeepConn,
NULL,
NULL);
if(fKeepConn)
dwStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
else
dwStatus = HSE_STATUS_SUCCESS;
ConnID = pecb->ConnID;
AssertSz(pecb->lpszQueryString,
"DwHandleContentRequest(): "
"NULL query string passed");
// Validate the method.
hr = HrValidateDescriptionMethod(pecb->lpszMethod);
if (SUCCEEDED(hr))
{
// Get the content GUID.
TraceTag(ttidUDHISAPI,
"DwHandleContentRequest(): ConnID(0x%x) "
"Query string is %s",
ConnID,
pecb->lpszQueryString);
hr = HrParseDescriptionQueryString(pecb->lpszQueryString,
guidContent);
if (SUCCEEDED(hr))
{
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IUPnPDynamicContentSource * pudcs = NULL;
hr = CoCreateInstance(CLSID_UPnPDynamicContentSource,
NULL,
CLSCTX_INPROC_SERVER,
IID_IUPnPDynamicContentSource,
(void **) &pudcs);
if (SUCCEEDED(hr))
{
hr = HrReturnContent(pecb,
pudcs,
guidContent);
pudcs->Release();
}
else
{
TraceTag(ttidUDHISAPI,
"DwHandleContentRequest(): ConnID(0x%x): "
"Failed to CoCreate dynamic content source, "
" HRESULT == 0x%x",
ConnID,
hr);
}
CoUninitialize();
}
else
{
TraceTag(ttidUDHISAPI,
"DwHandleContentRequest(): ConnID(0x%x): "
"Failed to initialize COM, HRESULT == 0x%x",
ConnID,
hr);
}
}
else
{
TraceTag(ttidUDHISAPI,
"DwHandleContentRequest(): ConnID(0x%x): "
"Failed to get content GUID, HRESULT == 0x%x",
ConnID,
hr);
}
}
else
{
TraceTag(ttidUDHISAPI,
"DwHandleContentRequest(): ConnID(0x%x): "
"Failed to validate method %s, HRESULT == 0x%x",
ConnID,
pecb->lpszMethod,
hr);
}
if (FAILED(hr))
{
LPCSTR pcszErrorHeaders = "\r\n";
dwStatus = HSE_STATUS_ERROR;
if (bSendResponseToClient(pecb,
"500 Internal Server Error",
lstrlenA(pcszErrorHeaders),
pcszErrorHeaders,
0,
NULL))
{
pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
}
}
return dwStatus ;
}