//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #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 ; }