📄 control.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "pch.h"
#pragma hdrstop
#include <httpext.h>
#include "http_status.h"
// default SOAP error response returned when there is an unknown error
// in the control request, but the request is syntactically ok
const CHAR c_szDefaultSOAPFault [] =
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"
" <SOAP-ENV:Body>\r\n"
" <SOAP-ENV:Fault>\r\n"
" <faultcode>SOAP-ENV:Client</faultcode>\r\n"
" <faultstring>UPnPError</faultstring>\r\n"
" <detail>\r\n"
" <UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\r\n"
" <errorCode>501</errorCode>\r\n"
" <errorDescription>Action Failed</errorDescription>\r\n"
" </UPnPError>\r\n"
" </detail>\r\n"
" </SOAP-ENV:Fault>\r\n"
" </SOAP-ENV:Body>\r\n"
"</SOAP-ENV:Envelope>";
ControlRequest::ControlRequest(LPEXTENSION_CONTROL_BLOCK pecb) :
m_pecb(pecb),
m_dwHttpStatus(HTTP_STATUS_OK),
m_pszServiceId(NULL),
m_pszUDN(NULL),
m_pszServiceType(NULL),
m_pszResponse(NULL),
m_pszRequestXML(NULL)
{
char pszHeaderBuf[100];
DWORD dw;
// POST action
if(!_stricmp(pecb->lpszMethod, "POST"))
{
TraceTag(ttidControl, "%s: POST Received\n", __FUNCTION__);
// SOAPACTION header required
if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_SOAPACTION", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
if(ERROR_NO_DATA == GetLastError())
{
// missing SOAPACTION header -> 400 Bad request
m_dwHttpStatus = HTTP_STATUS_BAD_REQUEST;
TraceTag(ttidControl, "%s: POST: Error retrieving HTTP_SOAPACTION parameter [%d]\n", __FUNCTION__, m_dwHttpStatus);
return;
}
TraceTag(ttidControl, "%s: POST: read HTTP_SOAPACTION parameter\n", __FUNCTION__);
}
// M-POST action
if(!_stricmp(pecb->lpszMethod, "M-POST"))
{
TraceTag(ttidControl, "%s: M-POST Received\n", __FUNCTION__);
// MAN header required
if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_MAN", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
if(ERROR_NO_DATA == GetLastError())
{
// missing MAN header -> 400 Bad request
m_dwHttpStatus = HTTP_STATUS_BAD_REQUEST;
TraceTag(ttidControl, "%s: M-POST: Error retrieving HTTP_MAN parameter [%d]\n", __FUNCTION__, m_dwHttpStatus);
return;
}
TraceTag(ttidControl, "%s: M-POST: read HTTP_MAN parameter\n", __FUNCTION__);
}
m_pDevTree = FindDevTreeAndServiceIdFromUri(m_pecb->lpszQueryString, &m_pszUDN, &m_pszServiceId);
TraceTag(ttidControl, "%s: HostedDeviceTree[%08x] UDN[%s], ServiceID[%s]\n", __FUNCTION__, m_pDevTree, m_pszUDN, m_pszServiceId);
if (!m_pDevTree)
{
// invalid UDN or service
m_dwHttpStatus = HTTP_STATUS_SERVER_ERROR;
TraceTag(ttidControl, "%s: Error retrieving HostedDeviceTree [%d]\n", __FUNCTION__, m_dwHttpStatus);
}
else if (!(m_pszRequestXML = new WCHAR [m_pecb->cbAvailable + 1]))
{
m_dwHttpStatus = HTTP_STATUS_SERVICE_UNAVAIL;
TraceTag(ttidControl, "%s: Error OOM allocating XML Request Buffer [%d]\n", __FUNCTION__, m_dwHttpStatus);
}
else
{
// we are relying on IIS behavior that pre-reads upto 48K of request data
Assert(m_pecb->cbAvailable == m_pecb->cbTotalBytes || m_pecb->cbTotalBytes == 0);
// need to convert the request body to UNICODE for the benefit of the XML parser
// UTF8 encoding
int cch;
if(!(cch = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)m_pecb->lpbData, m_pecb->cbAvailable, m_pszRequestXML, m_pecb->cbAvailable)))
cch = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)m_pecb->lpbData, m_pecb->cbAvailable, m_pszRequestXML, m_pecb->cbAvailable);
m_pszRequestXML[cch] = 0; // null terminate
TraceTag(ttidControl, "%s: Request XML [%S]\n", __FUNCTION__, m_pszRequestXML);
}
}
ControlRequest::~ControlRequest()
{
m_SvcCtl.Reserved1 = NULL; // this helps catch bogus callbacks after we're gone
delete m_pszServiceId; // allocated by FindDevTree...
delete m_pszServiceType;
if (m_pDevTree)
m_pDevTree->DecRef();
delete m_pszRequestXML;
delete m_pszResponse;
delete m_pszUDN;
}
//
// ForwardRequest is called to dispatch the parsed and validated request to the device implementation
BOOL
ControlRequest::ForwardRequest()
{
BOOL fRet;
TraceTag(ttidControl, "%s: Forwarding Control Request HostedDeviceTree[%08x]\n", __FUNCTION__, m_pDevTree);
Assert(m_pszServiceId);
Assert(m_pDevTree);
// call into the hosted device implementation
// this will usually cross the process boundary
// the device is expected to set any output parameters
// this is accomplished by calling back into SetRawControlResponse
fRet = m_pDevTree->Control(this);
// if the actual device has not responded then we need
// to come up with a default fault response
if (!m_pszResponse)
fRet = FALSE;
if (!fRet)
{
m_dwHttpStatus = HTTP_STATUS_SERVER_ERROR;
TraceTag(ttidControl, "%s: Device has not responded returning default error [%08x] [%d]\n", __FUNCTION__, m_pDevTree, m_dwHttpStatus);
}
TraceTag(ttidControl, "%s: Completed Forward Request for HostedDeviceTree[%08x] [%S]\n", __FUNCTION__, m_pDevTree, fRet ? L"TRUE" : L"FALSE");
return fRet;
}
BOOL
ControlRequest::SendResponse()
{
HSE_SEND_HEADER_EX_INFO hse;
CHAR szHeader[256];
PSTR pszResponse;
DWORD cbResponse;
TraceTag(ttidControl, "%s: Sending Control Request Response\n", __FUNCTION__);
if(m_pszResponse)
pszResponse = m_pszResponse;
else
// If the actual device has not responded then we need
// to come up with a default fault response
pszResponse = const_cast<PSTR>(c_szDefaultSOAPFault);
cbResponse = strlen(pszResponse);
TraceTag(ttidControl, "%s: Response Size [%d] Response XML\n", __FUNCTION__, cbResponse);
hse.pszStatus = ce::http_status_string(m_dwHttpStatus);
hse.pszHeader = NULL; // Should be empty for HTTP errors.other than 500
hse.cchStatus = strlen(hse.pszStatus);
hse.cchHeader = 0;
hse.fKeepConn = FALSE;
if (pszResponse && cbResponse)
{
hse.cchHeader = _snprintf(szHeader, sizeof(szHeader),
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"Content-Length: %d\r\n"
"EXT:\r\n"
"\r\n", cbResponse);
hse.pszHeader = szHeader;
hse.fKeepConn = TRUE;
}
m_pecb->dwHttpStatusCode = m_dwHttpStatus;
m_pecb->ServerSupportFunction(m_pecb->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
(LPVOID)&hse,
NULL,
NULL
);
m_pecb->WriteClient(m_pecb->ConnID,pszResponse,&cbResponse,NULL);
TraceTag(ttidControl, "%s: Finished Sending Control Request Response\n", __FUNCTION__);
return TRUE;
}
ControlRequest::SetResponse(DWORD dwHttpStatus, PCWSTR pszResp)
{
Assert(!m_pszResponse);
if (m_pszResponse)
return FALSE;
m_dwHttpStatus = dwHttpStatus;
UINT cp = CP_UTF8;
DWORD cbResponse;
cbResponse = WideCharToMultiByte(cp, 0, pszResp, -1, NULL, 0, NULL, NULL);
TraceTag(ttidControl, "%s: [%08x] Setting Response\n", __FUNCTION__, this);
TraceTag(ttidControl, "%s: [%08x] Response[%S]\n", __FUNCTION__, this, pszResp);
TraceTag(ttidControl, "%s: [%08x] Response Size[%d]\n", __FUNCTION__, this, cbResponse);
if(!cbResponse)
if(cbResponse = WideCharToMultiByte(CP_ACP, 0, pszResp, -1, NULL, 0, NULL, NULL))
cp = CP_ACP;
if(m_pszResponse = new char[cbResponse])
WideCharToMultiByte(cp, 0, pszResp, -1, m_pszResponse, cbResponse, NULL, NULL);
return (m_pszResponse != NULL);
}
// This is the ISAPI extension handler for UPNP control requests
DWORD ControlExtensionProc(LPEXTENSION_CONTROL_BLOCK pecb)
{
ControlRequest creq(pecb);
TraceTag(ttidControl, "%s: Processing Control Request for UDN[%s], ServiceID[%S]\n", __FUNCTION__, creq.UDN(), creq.ServiceId());
TraceTag(ttidControl, "%s: Processing Control Request for RequestXML[%S]\n", __FUNCTION__, creq.RequestXML());
Assert(pecb->cbAvailable && pecb->lpbData);
if (creq.StatusOk())
{
creq.ForwardRequest();
}
creq.SendResponse();
return HSE_STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -