387 lines
10 KiB
C++
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 ;
|
||
|
}
|