|
|
//+---------------------------------------------------------------------------
//
// 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 ; }
|