Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2550 lines
81 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: C T R L R Q S T . C P P
  7. //
  8. // Contents: Implementation of control request processing for the
  9. // UPnP Device Host ISAPI Extension
  10. //
  11. // Notes:
  12. //
  13. // Author: spather 2000/08/31
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include <wininet.h>
  19. #include <msxml2.h>
  20. #include "ctrlrqst.h"
  21. #include "udhiutil.h"
  22. #include "hostp.h"
  23. #include "ncbase.h"
  24. #include "ncxml.h"
  25. #include "ValidateSOAP.h"
  26. const WCHAR WSZ_SOAP_NAMESPACE_URI[] =
  27. L"http://schemas.xmlsoap.org/soap/envelope/";
  28. const WCHAR WSZ_UPNP_NAMESPACE_URI[] =
  29. L"urn:schemas-upnp-org:control-1-0";
  30. //+---------------------------------------------------------------------------
  31. //
  32. // Function: CleanupSerializedRequest
  33. //
  34. // Purpose: Frees resources used by the fields of a UPNP_SOAP_REQUEST
  35. // structure
  36. //
  37. // Arguments:
  38. // pusr [in] Address of the structure to cleanup
  39. //
  40. // Returns:
  41. // (none)
  42. //
  43. // Author: spather 2000/09/24
  44. //
  45. // Notes:
  46. // This function just frees the resources used by the fields within
  47. // the passed in structure. It does not free the memory used by the
  48. // structure itself.
  49. //
  50. VOID
  51. CleanupSerializedRequest(
  52. IN UPNP_SOAP_REQUEST * pusr)
  53. {
  54. if (pusr->bstrActionName)
  55. {
  56. SysFreeString(pusr->bstrActionName);
  57. pusr->bstrActionName = NULL;
  58. }
  59. if (pusr->pxdnlArgs)
  60. {
  61. pusr->pxdnlArgs->Release();
  62. pusr->pxdnlArgs = NULL;
  63. }
  64. }
  65. //+---------------------------------------------------------------------------
  66. //
  67. // Function: CleanupSerializedResponse
  68. //
  69. // Purpose: Frees resources used by the fields of a UPNP_SOAP_RESPONSE
  70. // structure
  71. //
  72. // Arguments:
  73. // pusr [in] Address of the structure to cleanup
  74. //
  75. // Returns:
  76. // (none)
  77. //
  78. // Author: spather 2000/09/24
  79. //
  80. // Notes:
  81. // This function just frees the resources used by the fields within
  82. // the passed in structure. It does not free the memory used by the
  83. // structure itself.
  84. //
  85. VOID
  86. CleanupSerializedResponse(
  87. IN UPNP_SOAP_RESPONSE * pusr)
  88. {
  89. if (pusr->pxddRespEnvelope)
  90. {
  91. pusr->pxddRespEnvelope->Release();
  92. pusr->pxddRespEnvelope = NULL;
  93. }
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Function: CleanupDeserializedRequest
  98. //
  99. // Purpose: Frees resources used by the fields of a UPNP_CONTROL_REQUEST
  100. // structure
  101. //
  102. // Arguments:
  103. // pucr [in] Address of the structure to cleanup
  104. //
  105. // Returns:
  106. // (none)
  107. //
  108. // Author: spather 2000/09/24
  109. //
  110. // Notes:
  111. // This function just frees the resources used by the fields within
  112. // the passed in structure. It does not free the memory used by the
  113. // structure itself.
  114. //
  115. VOID
  116. CleanupDeserializedRequest(
  117. IN UPNP_CONTROL_REQUEST * pucr)
  118. {
  119. if (pucr->bstrActionName)
  120. {
  121. SysFreeString(pucr->bstrActionName);
  122. pucr->bstrActionName = NULL;
  123. }
  124. if (pucr->rgvarInputArgs)
  125. {
  126. for (DWORD i = 0; i < pucr->cInputArgs; i++)
  127. {
  128. VariantClear(&pucr->rgvarInputArgs[i]);
  129. }
  130. delete [] pucr->rgvarInputArgs;
  131. pucr->rgvarInputArgs = NULL;
  132. pucr->cInputArgs = 0;
  133. }
  134. }
  135. //+---------------------------------------------------------------------------
  136. //
  137. // Function: CleanupResponseData
  138. //
  139. // Purpose: Frees resources of a UPNP_CONTROL_RESPONSE_DATA
  140. // structure
  141. //
  142. // Arguments:
  143. // pucr [in] Address of the structure to cleanup
  144. // fSucceeded [in] Whether the structure is valid for success
  145. //
  146. // Returns:
  147. // (none)
  148. //
  149. // Author: spather 2000/09/24
  150. //
  151. // Notes:
  152. // This function just frees the resources used by the fields within
  153. // the passed in structure. It does not free the memory used by the
  154. // structure itself.
  155. //
  156. VOID
  157. CleanupResponseData(
  158. IN UPNP_CONTROL_RESPONSE_DATA * pucrd,
  159. IN BOOL fSucceeded)
  160. {
  161. Assert(pucrd);
  162. if (fSucceeded)
  163. {
  164. if (pucrd->Success.rgvarOutputArgs)
  165. {
  166. for (DWORD i = 0; i < pucrd->Success.cOutputArgs; i++)
  167. {
  168. VariantClear(&pucrd->Success.rgvarOutputArgs[i]);
  169. }
  170. CoTaskMemFree(pucrd->Success.rgvarOutputArgs);
  171. pucrd->Success.rgvarOutputArgs = NULL;
  172. pucrd->Success.cOutputArgs = 0;
  173. }
  174. }
  175. else
  176. {
  177. if (pucrd->Fault.bstrFaultCode)
  178. {
  179. SysFreeString(pucrd->Fault.bstrFaultCode);
  180. pucrd->Fault.bstrFaultCode = NULL;
  181. }
  182. if (pucrd->Fault.bstrFaultString)
  183. {
  184. SysFreeString(pucrd->Fault.bstrFaultString);
  185. pucrd->Fault.bstrFaultString = NULL;
  186. }
  187. if (pucrd->Fault.bstrUPnPErrorCode)
  188. {
  189. SysFreeString(pucrd->Fault.bstrUPnPErrorCode);
  190. pucrd->Fault.bstrUPnPErrorCode = NULL;
  191. }
  192. if (pucrd->Fault.bstrUPnPErrorString)
  193. {
  194. SysFreeString(pucrd->Fault.bstrUPnPErrorString);
  195. pucrd->Fault.bstrUPnPErrorString = NULL;
  196. }
  197. }
  198. }
  199. //+---------------------------------------------------------------------------
  200. //
  201. // Function: CleanupDeserializedResponse
  202. //
  203. // Purpose: Frees resources used by the fields of a UPNP_CONTROL_RESPONSE
  204. // structure
  205. //
  206. // Arguments:
  207. // pucr [in] Address of the structure to cleanup
  208. //
  209. // Returns:
  210. // (none)
  211. //
  212. // Author: spather 2000/09/24
  213. //
  214. // Notes:
  215. // This function just frees the resources used by the fields within
  216. // the passed in structure. It does not free the memory used by the
  217. // structure itself.
  218. //
  219. VOID
  220. CleanupDeserializedResponse(
  221. IN UPNP_CONTROL_RESPONSE * pucresp)
  222. {
  223. if (pucresp->bstrActionName)
  224. {
  225. SysFreeString(pucresp->bstrActionName);
  226. pucresp->bstrActionName = NULL;
  227. }
  228. CleanupResponseData(&pucresp->ucrData, pucresp->fSucceeded);
  229. }
  230. //+---------------------------------------------------------------------------
  231. //
  232. // Function: HrValidateControlMethod
  233. //
  234. // Purpose: Validates that the HTTP verb used is valid for this
  235. // type of request.
  236. //
  237. // Arguments:
  238. // pszaMethod [in] The HTTP verb
  239. //
  240. // Returns:
  241. // If the method is valid, the return value is S_OK. If the method is
  242. // not valid, the function returns one of the COM error codes defined
  243. // in WinError.h.
  244. //
  245. // Author: spather 2000/09/21
  246. //
  247. // Notes:
  248. //
  249. HRESULT
  250. HrValidateControlMethod(
  251. IN LPSTR pszaMethod)
  252. {
  253. HRESULT hr = S_OK;
  254. AssertSz(pszaMethod,
  255. "HrValidateControlMethod(): NULL Method passed");
  256. if ((0 != lstrcmpiA(pszaMethod, "POST")) &&
  257. (0 != lstrcmpiA(pszaMethod, "M-POST")))
  258. {
  259. if (0 == lstrcmpiA(pszaMethod, "GET") ||
  260. 0 == lstrcmpiA(pszaMethod, "HEAD"))
  261. {
  262. hr = UPNP_E_METHOD_NOT_ALLOWED;
  263. }
  264. else
  265. {
  266. hr = UPNP_E_METHOD_NOT_IMPLEMENTED;
  267. }
  268. }
  269. TraceError("HrValidateControlMethod(): Exiting",
  270. hr);
  271. return hr;
  272. }
  273. //+---------------------------------------------------------------------------
  274. //
  275. // Function: HrWriteResponse
  276. //
  277. // Purpose: Writes a control response back to the client
  278. //
  279. // Arguments:
  280. // pecb [in] The extension control block for the request
  281. // pxdnRespEnvelope [in] The XML DOM node representing the response
  282. // envelope
  283. // fSucceeded [in] Indicates whether or not this is a success
  284. // response
  285. //
  286. // Returns:
  287. // If the function succeeds, the return value is S_OK. Otherwise, the
  288. // function returns one of the COM error codes defined in WinError.h.
  289. //
  290. // Author: spather 2000/09/25
  291. //
  292. // Notes:
  293. //
  294. HRESULT
  295. HrWriteResponse(
  296. IN LPEXTENSION_CONTROL_BLOCK pecb,
  297. IN IXMLDOMDocument * pxddRespEnvelope,
  298. IN BOOL fSucceeded)
  299. {
  300. HRESULT hr = S_OK;
  301. BSTR bstrRespEnvelope = NULL;
  302. DWORD cchRespEnvelope = 0;
  303. LPSTR pszaRespEnvelope = NULL;
  304. DWORD cchHeaders = 0;
  305. CHAR szaHeaders[256];
  306. LPCSTR pcszaHeadersFmt =
  307. "Content-Length: %d\r\n"
  308. "Content-Type: text/xml; charset=\"utf-8\"\r\n"
  309. "EXT:\r\n\r\n";
  310. // Convert response envelope to UTF-8 string.
  311. hr = pxddRespEnvelope->get_xml(&bstrRespEnvelope);
  312. if (SUCCEEDED(hr))
  313. {
  314. pszaRespEnvelope = Utf8FromWsz(bstrRespEnvelope);
  315. if (pszaRespEnvelope)
  316. {
  317. cchRespEnvelope = lstrlenA(pszaRespEnvelope);
  318. TraceTag(ttidUDHISAPI,
  319. "HrWriteResponse(): "
  320. "Sending response:\n"
  321. "%s",
  322. pszaRespEnvelope);
  323. }
  324. else
  325. {
  326. hr = E_OUTOFMEMORY;
  327. TraceError("HrWriteResponse(): "
  328. "Failed to convert response envelope to ANSI",
  329. hr);
  330. }
  331. SysFreeString(bstrRespEnvelope);
  332. }
  333. else
  334. {
  335. TraceError("HrWriteResponse(): "
  336. "Failed to get envelope XML text",
  337. hr);
  338. }
  339. wsprintfA(szaHeaders, pcszaHeadersFmt, cchRespEnvelope);
  340. cchHeaders = lstrlenA(szaHeaders);
  341. if (fSucceeded)
  342. {
  343. // Success response, so HTTP status is 200 OK
  344. if (bSendResponseToClient(pecb,
  345. "200 OK",
  346. cchHeaders,
  347. szaHeaders,
  348. cchRespEnvelope,
  349. pszaRespEnvelope))
  350. {
  351. pecb->dwHttpStatusCode = HTTP_STATUS_OK;
  352. TraceTag(ttidUDHISAPI,
  353. "HrWriteResponse(): "
  354. "Successfully sent success response");
  355. }
  356. else
  357. {
  358. hr = HrFromLastWin32Error();
  359. TraceLastWin32Error("HrWriteResponse(): "
  360. "Failed to send success response to client");
  361. }
  362. }
  363. else
  364. {
  365. // Failure response, so HTTP status is 500 Internal Server Error
  366. if (bSendResponseToClient(pecb,
  367. "500 Internal Server Error",
  368. cchHeaders,
  369. szaHeaders,
  370. cchRespEnvelope,
  371. pszaRespEnvelope))
  372. {
  373. pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  374. TraceTag(ttidUDHISAPI,
  375. "HrWriteResponse(): "
  376. "Successfully sent error response");
  377. }
  378. else
  379. {
  380. hr = HrFromLastWin32Error();
  381. TraceLastWin32Error("HrWriteResponse(): "
  382. "Failed to send error response to client");
  383. }
  384. }
  385. if (pszaRespEnvelope)
  386. {
  387. delete [] pszaRespEnvelope;
  388. pszaRespEnvelope = NULL;
  389. cchRespEnvelope = 0;
  390. }
  391. TraceError("HrWriteResponse(): "
  392. "Exiting",
  393. hr);
  394. return hr;
  395. }
  396. //+---------------------------------------------------------------------------
  397. //
  398. // Function: HrAppendFaultElementToBody
  399. //
  400. // Purpose: Appends a SOAP fault element to a body element. The fault
  401. // element contains a SOAP fault code, fault string, and possibly
  402. // a detail element containing a UPnP error code and error string.
  403. //
  404. // Arguments:
  405. // pxdd [in] Document object to use to create elements
  406. // pxdnBody [in] The body element
  407. // pucrespDeserialized [in] The deserialized response info
  408. //
  409. // Returns:
  410. // If the function succeeds, the return value is S_OK. Otherwise, the
  411. // function returns one of the COM error codes defined in WinError.h.
  412. //
  413. // Author: spather 2000/09/26
  414. //
  415. // Notes:
  416. //
  417. HRESULT
  418. HrAppendFaultElementToBody(
  419. IN IXMLDOMDocument * pxdd,
  420. IN IXMLDOMNode * pxdnBody,
  421. IN UPNP_CONTROL_RESPONSE * pucrespDeserialized)
  422. {
  423. HRESULT hr = S_OK;
  424. IXMLDOMNode * pxdnFault = NULL;
  425. IXMLDOMElement * pxdeFaultCode = NULL;
  426. IXMLDOMElement * pxdeFaultString = NULL;
  427. IXMLDOMNode * pxdnDetail = NULL;
  428. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  429. pucrd = &pucrespDeserialized->ucrData;
  430. // Create the fault element.
  431. hr = HrCreateElement(pxdd,
  432. L"SOAP-ENV:Fault",
  433. WSZ_SOAP_NAMESPACE_URI,
  434. &pxdnFault);
  435. if (SUCCEEDED(hr))
  436. {
  437. Assert(pxdnFault);
  438. // Create the Fault element's children.
  439. hr = HrCreateElementWithTextValue(pxdd,
  440. L"faultcode",
  441. pucrd->Fault.bstrFaultCode,
  442. &pxdeFaultCode);
  443. if (SUCCEEDED(hr))
  444. {
  445. Assert(pxdeFaultCode);
  446. hr = HrCreateElementWithTextValue(pxdd,
  447. L"faultstring",
  448. pucrd->Fault.bstrFaultString,
  449. &pxdeFaultString);
  450. if (SUCCEEDED(hr))
  451. {
  452. Assert(pxdeFaultString);
  453. hr = HrCreateElement(pxdd,
  454. L"detail",
  455. NULL,
  456. &pxdnDetail);
  457. if (SUCCEEDED(hr))
  458. {
  459. IXMLDOMNode * pxdnUPnPError = NULL;
  460. hr = HrCreateElement(pxdd,
  461. L"UPnPError",
  462. WSZ_UPNP_NAMESPACE_URI,
  463. &pxdnUPnPError);
  464. if (SUCCEEDED(hr))
  465. {
  466. IXMLDOMElement * pxdeErrorCode = NULL;
  467. Assert(pxdnUPnPError);
  468. // Add children to UPnPError.
  469. hr = HrCreateElementWithTextValue(pxdd,
  470. L"errorCode",
  471. pucrd->Fault.bstrUPnPErrorCode,
  472. &pxdeErrorCode);
  473. if (SUCCEEDED(hr))
  474. {
  475. Assert(pxdeErrorCode);
  476. hr = pxdnUPnPError->appendChild(pxdeErrorCode,
  477. NULL);
  478. if (SUCCEEDED(hr))
  479. {
  480. IXMLDOMElement * pxdeErrorDesc = NULL;
  481. hr = HrCreateElementWithTextValue(pxdd,
  482. L"errorDescription",
  483. pucrd->Fault.bstrUPnPErrorString,
  484. &pxdeErrorDesc);
  485. if (SUCCEEDED(hr))
  486. {
  487. Assert(pxdeErrorDesc);
  488. hr = pxdnUPnPError->appendChild(pxdeErrorDesc,
  489. NULL);
  490. if (SUCCEEDED(hr))
  491. {
  492. TraceTag(ttidUDHISAPI,
  493. "HrAppendFaultElementToBody(): "
  494. "Successfully appended errorCode "
  495. "and errorDescription elements");
  496. }
  497. else
  498. {
  499. TraceError("HrAppendFaultElementToBody(): "
  500. "Failed to append errorCode element",
  501. hr);
  502. }
  503. pxdeErrorDesc->Release();
  504. }
  505. else
  506. {
  507. TraceError("HrAppendFaultElementToBody(): "
  508. "Failed to create errorDescription element",
  509. hr);
  510. }
  511. }
  512. else
  513. {
  514. TraceError("HrAppendFaultElementToBody(): "
  515. "Failed to append errorCode element",
  516. hr);
  517. }
  518. pxdeErrorCode->Release();
  519. }
  520. else
  521. {
  522. TraceError("HrAppendFaultElementToBody(): "
  523. "Failed to create errorCode element",
  524. hr);
  525. }
  526. // If successful, attach UPnPError to detail.
  527. if (SUCCEEDED(hr))
  528. {
  529. hr = pxdnDetail->appendChild(pxdnUPnPError,
  530. NULL);
  531. if (SUCCEEDED(hr))
  532. {
  533. TraceTag(ttidUDHISAPI,
  534. "HrAppendFaultElementToBody(): "
  535. "Successfully appended UPnPError "
  536. "element");
  537. }
  538. else
  539. {
  540. TraceError("HrAppendFaultElementToBody(): "
  541. "Failed to append UPnPError",
  542. hr);
  543. }
  544. }
  545. pxdnUPnPError->Release();
  546. }
  547. else
  548. {
  549. TraceError("HrAppendFaultElementToBody(): "
  550. "Failed to create UPnPError element",
  551. hr);
  552. }
  553. }
  554. else
  555. {
  556. TraceError("HrAppendFaultElementToBody(): "
  557. "Failed to create detail element",
  558. hr);
  559. }
  560. }
  561. else
  562. {
  563. TraceError("HrAppendFaultElementToBody(): "
  564. "Failed to create fault string element",
  565. hr);
  566. }
  567. }
  568. else
  569. {
  570. TraceError("HrAppendFaultElementToBody(): "
  571. "Failed to create fault code element",
  572. hr);
  573. }
  574. // Attach the Fault element's children.
  575. if (SUCCEEDED(hr))
  576. {
  577. Assert(pxdeFaultCode);
  578. Assert(pxdeFaultString);
  579. Assert(pxdnDetail);
  580. hr = pxdnFault->appendChild(pxdeFaultCode, NULL);
  581. if (SUCCEEDED(hr))
  582. {
  583. TraceTag(ttidUDHISAPI,
  584. "HrAppendFaultElementToBody(): "
  585. "Successfully appended fault code element");
  586. hr = pxdnFault->appendChild(pxdeFaultString, NULL);
  587. if (SUCCEEDED(hr))
  588. {
  589. TraceTag(ttidUDHISAPI,
  590. "HrAppendFaultElementToBody(): "
  591. "Successfully appended fault string element");
  592. hr = pxdnFault->appendChild(pxdnDetail, NULL);
  593. if (SUCCEEDED(hr))
  594. {
  595. TraceTag(ttidUDHISAPI,
  596. "HrAppendFaultElementToBody(): "
  597. "Successfully appended detail element");
  598. }
  599. else
  600. {
  601. TraceError("HrAppendFaultElementToBody(): "
  602. "Failed to append detail element",
  603. hr);
  604. }
  605. }
  606. else
  607. {
  608. TraceError("HrAppendFaultElementToBody(): "
  609. "Failed to append fault string element",
  610. hr);
  611. }
  612. }
  613. else
  614. {
  615. TraceError("HrAppendFaultElementToBody(): "
  616. "Failed to append fault code element",
  617. hr);
  618. }
  619. }
  620. // If everything succeeded, then append the fault element to the body.
  621. if (SUCCEEDED(hr))
  622. {
  623. hr = pxdnBody->appendChild(pxdnFault,
  624. NULL);
  625. if (SUCCEEDED(hr))
  626. {
  627. TraceTag(ttidUDHISAPI,
  628. "HrAppendFaultElementToBody(): "
  629. "Successfully appended fault element to body");
  630. }
  631. else
  632. {
  633. TraceError("HrAppendFaultElementToBody(): "
  634. "Failed to append fault element to body",
  635. hr);
  636. }
  637. }
  638. // Clean up.
  639. if (pxdeFaultCode)
  640. {
  641. pxdeFaultCode->Release();
  642. pxdeFaultCode = NULL;
  643. }
  644. if (pxdeFaultString)
  645. {
  646. pxdeFaultString->Release();
  647. pxdeFaultString = NULL;
  648. }
  649. if (pxdnDetail)
  650. {
  651. pxdnDetail->Release();
  652. pxdnDetail = NULL;
  653. }
  654. pxdnFault->Release();
  655. }
  656. else
  657. {
  658. TraceError("HrAppendFaultElementToBody(): "
  659. "Failed to create fault element",
  660. hr);
  661. }
  662. TraceError("HrAppendFaultElementToBody(): "
  663. "Exiting",
  664. hr);
  665. return hr;
  666. }
  667. //+---------------------------------------------------------------------------
  668. //
  669. // Function: HrAppendActionResponseElementToBody
  670. //
  671. // Purpose: Appends an action response XML element to a body element.
  672. // The action response element contains the action name and
  673. // the output arguments.
  674. //
  675. // Arguments:
  676. // pxdd [in] Document object to use to create elements
  677. // pxdnBody [in] The body element
  678. // pucrDeserialized [in] Address of the deserialized request structure
  679. // (needed only for the QueryStateVariable case,
  680. // to get the variable name)
  681. // pucrespDeserialized [in] The deserialized response info
  682. // pServiceDescInfo [in] Service Description Info object for the
  683. // service
  684. //
  685. // Returns:
  686. // If the function succeeds, the return value is S_OK. Otherwise, the
  687. // function returns one of the COM error codes defined in WinError.h.
  688. //
  689. // Author: spather 2000/09/26
  690. //
  691. // Notes:
  692. //
  693. HRESULT
  694. HrAppendActionResponseElementToBody(
  695. IN IUPnPAutomationProxy * pAutomationProxy,
  696. IN IXMLDOMDocument * pxdd,
  697. IN IXMLDOMNode * pxdnBody,
  698. IN UPNP_CONTROL_REQUEST * pucrDeserialized,
  699. IN UPNP_CONTROL_RESPONSE * pucrespDeserialized,
  700. IN IUPnPServiceDescriptionInfo * pServiceDescInfo)
  701. {
  702. HRESULT hr = S_OK;
  703. DWORD cchSuffix = 0;
  704. DWORD cchPrefix = 0;
  705. LPCWSTR pcszSuffix = L"Response";
  706. LPCWSTR pcszPrefix = L"m:";
  707. DWORD cchElementName = 0;
  708. LPWSTR pszElementName = NULL;
  709. BOOL bIsQsv = FALSE;
  710. cchSuffix = lstrlenW(pcszSuffix);
  711. cchPrefix = lstrlenW(pcszPrefix);
  712. cchElementName = SysStringLen(pucrespDeserialized->bstrActionName) +
  713. cchSuffix + cchPrefix;
  714. pszElementName = new WCHAR[cchElementName+1];
  715. bIsQsv = (0 == lstrcmpW(pucrespDeserialized->bstrActionName, L"QueryStateVariable"));
  716. if (pszElementName)
  717. {
  718. IXMLDOMNode * pxdnActionResponse = NULL;
  719. wsprintfW(pszElementName,
  720. L"%s%s%s",
  721. pcszPrefix,
  722. pucrespDeserialized->bstrActionName,
  723. pcszSuffix);
  724. LPWSTR pszServiceType;
  725. hr = pAutomationProxy->GetServiceType(&pszServiceType);
  726. if (SUCCEEDED(hr))
  727. {
  728. if (bIsQsv)
  729. {
  730. hr = HrCreateElement(pxdd,
  731. pszElementName,
  732. WSZ_UPNP_NAMESPACE_URI,
  733. &pxdnActionResponse);
  734. }
  735. else
  736. {
  737. hr = HrCreateElement(pxdd,
  738. pszElementName,
  739. pszServiceType,
  740. &pxdnActionResponse);
  741. }
  742. CoTaskMemFree(pszServiceType);
  743. if (SUCCEEDED(hr))
  744. {
  745. UPNP_CONTROL_RESPONSE_DATA * pucrd = NULL;
  746. pucrd = &pucrespDeserialized->ucrData;
  747. if (pucrd->Success.cOutputArgs)
  748. {
  749. DWORD cOutputArgs = 0;
  750. BSTR * rgbstrNames = NULL;
  751. BSTR * rgbstrTypes = NULL;
  752. if (bIsQsv)
  753. {
  754. // Special case for QueryStateVariable.
  755. // We know there is one "output argument" called
  756. // "return" and its data type is the type of the
  757. // variable being queried.
  758. cOutputArgs = 1;
  759. rgbstrNames = (BSTR *) CoTaskMemAlloc(sizeof(BSTR));
  760. rgbstrTypes = (BSTR *) CoTaskMemAlloc(sizeof(BSTR));
  761. if (rgbstrNames && rgbstrTypes)
  762. {
  763. rgbstrNames[0] = SysAllocString(L"return");
  764. if (rgbstrNames[0])
  765. {
  766. rgbstrTypes[0] = NULL;
  767. hr = pServiceDescInfo->GetVariableType(
  768. V_BSTR(&pucrDeserialized->rgvarInputArgs[0]),
  769. &rgbstrTypes[0]);
  770. }
  771. else
  772. {
  773. hr = E_OUTOFMEMORY;
  774. }
  775. }
  776. else
  777. {
  778. hr = E_OUTOFMEMORY;
  779. }
  780. if (SUCCEEDED(hr))
  781. {
  782. TraceTag(ttidUDHISAPI,
  783. "HrAppendActionResponseElementToBody(): "
  784. "Successfully obtained out arg name and data "
  785. "type for QueryStateVariable");
  786. }
  787. else
  788. {
  789. TraceError("HrAppendActionResponseElementToBody(): "
  790. "Failed to obtain out arg name and data "
  791. "type for QueryStateVariable",
  792. hr);
  793. if (rgbstrNames)
  794. {
  795. if (rgbstrNames[0])
  796. {
  797. SysFreeString(rgbstrNames[0]);
  798. rgbstrNames[0] = NULL;
  799. }
  800. CoTaskMemFree(rgbstrNames);
  801. rgbstrNames = NULL;
  802. }
  803. if (rgbstrTypes)
  804. {
  805. if (rgbstrTypes[0])
  806. {
  807. SysFreeString(rgbstrTypes[0]);
  808. rgbstrTypes[0] = NULL;
  809. }
  810. CoTaskMemFree(rgbstrTypes);
  811. rgbstrTypes = NULL;
  812. }
  813. }
  814. }
  815. else
  816. {
  817. hr = pServiceDescInfo->GetOutputArgumentNamesAndTypes(
  818. pucrespDeserialized->bstrActionName,
  819. &cOutputArgs,
  820. &rgbstrNames,
  821. &rgbstrTypes);
  822. if (SUCCEEDED(hr))
  823. {
  824. TraceTag(ttidUDHISAPI,
  825. "HrAppendActionResponseElementToBody(): "
  826. "Successfully obtained out arg name and data "
  827. "type for action %S",
  828. pucrespDeserialized->bstrActionName);
  829. }
  830. else
  831. {
  832. TraceError("HrAppendActionResponseElementToBody(): "
  833. "Failed to obtain out arg name and data "
  834. "for action",
  835. hr);
  836. }
  837. }
  838. if (SUCCEEDED(hr))
  839. {
  840. Assert(cOutputArgs == pucrd->Success.cOutputArgs);
  841. Assert(rgbstrNames);
  842. Assert(rgbstrTypes);
  843. for (DWORD i = 0;
  844. SUCCEEDED(hr) && (i < cOutputArgs);
  845. i++)
  846. {
  847. IXMLDOMElement * pxdeArg = NULL;
  848. WCHAR * pwszArgName;
  849. pwszArgName = new WCHAR[lstrlenW(rgbstrNames[i]) + 1];
  850. if (NULL == pwszArgName)
  851. {
  852. hr = E_OUTOFMEMORY;
  853. }
  854. if (SUCCEEDED(hr))
  855. {
  856. lstrcpyW(pwszArgName, rgbstrNames[i]);
  857. hr = HrCreateElementWithType(pxdd,
  858. pwszArgName,
  859. rgbstrTypes[i],
  860. pucrd->Success.rgvarOutputArgs[i],
  861. &pxdeArg);
  862. delete [] pwszArgName;
  863. }
  864. if (SUCCEEDED(hr))
  865. {
  866. hr = pxdnActionResponse->appendChild(pxdeArg,
  867. NULL);
  868. if (SUCCEEDED(hr))
  869. {
  870. TraceTag(ttidUDHISAPI,
  871. "HrAppendActionResponseElementToBody(): "
  872. "Successfully appended element for "
  873. "argument %S",
  874. rgbstrNames[i]);
  875. }
  876. else
  877. {
  878. TraceError("HrAppendActionResponseElementToBody(): "
  879. "Failed to append argument element",
  880. hr);
  881. }
  882. pxdeArg->Release();
  883. }
  884. else if (E_FAIL == hr)
  885. {
  886. // something inside MSXML failed trying to put the value
  887. // most likely, this is caused by an un-coercible type
  888. TraceError("HrAppendActionResponseElementToBody(): "
  889. "Probably failed to coerce argument element",
  890. hr);
  891. hr = UPNP_E_DEVICE_ERROR;
  892. }
  893. else
  894. {
  895. TraceError("HrAppendActionResponseElementToBody(): "
  896. "Failed to get create argument element",
  897. hr);
  898. }
  899. }
  900. // Clean up.
  901. for (DWORD i = 0; i < cOutputArgs; i++)
  902. {
  903. SysFreeString(rgbstrNames[i]);
  904. rgbstrNames[i] = NULL;
  905. SysFreeString(rgbstrTypes[i]);
  906. rgbstrTypes[i] = NULL;
  907. }
  908. CoTaskMemFree(rgbstrNames);
  909. rgbstrNames = NULL;
  910. CoTaskMemFree(rgbstrTypes);
  911. rgbstrTypes = NULL;
  912. }
  913. }
  914. // If everything went ok, append action response element to
  915. // body.
  916. if (SUCCEEDED(hr))
  917. {
  918. hr = pxdnBody->appendChild(pxdnActionResponse, NULL);
  919. if (SUCCEEDED(hr))
  920. {
  921. TraceTag(ttidUDHISAPI,
  922. "HrAppendActionResponseElementToBody(): "
  923. "Successfully appended %S element to body",
  924. pszElementName);
  925. }
  926. else
  927. {
  928. TraceError("HrAppendActionResponseElementToBody(): "
  929. "Failed to append action response element",
  930. hr);
  931. }
  932. }
  933. pxdnActionResponse->Release();
  934. }
  935. else
  936. {
  937. TraceError("HrAppendActionResponseElementToBody(): "
  938. "Failed to create action response element",
  939. hr);
  940. }
  941. }
  942. else
  943. {
  944. TraceError("HrAppendActionResponseElementToBody(): "
  945. "Failed to get service type", hr);
  946. }
  947. delete [] pszElementName;
  948. pszElementName = NULL;
  949. }
  950. else
  951. {
  952. hr = E_OUTOFMEMORY;
  953. TraceError("HrAppendActionResponseElementToBody(): "
  954. "Failed to allocate memory for action "
  955. "response element name",
  956. hr);
  957. }
  958. TraceError("HrAppendActionResponseElementToBody(): "
  959. "Exiting",
  960. hr);
  961. return hr;
  962. }
  963. //+---------------------------------------------------------------------------
  964. //
  965. // Function: HrSerializeResponse
  966. //
  967. // Purpose: Serializes response information.
  968. //
  969. // Arguments:
  970. // pucrDeserialized [in] Address of the deserialized request structure
  971. // (needed only for the QueryStateVariable case,
  972. // to get the variable name)
  973. // pucrespDeserialized [in] Address of structure containing deserialized
  974. // response info
  975. // pServiceDescInfo [in] Service Description Info object for the
  976. // service
  977. // pusrespSerialized [in] Address of structure whose fields will be
  978. // initialized with serialized response info
  979. //
  980. // Returns:
  981. // If the function succeeds, the return value is S_OK. Otherwise, the
  982. // function returns one of the COM error codes defined in WinError.h.
  983. //
  984. // Author: spather 2000/09/25
  985. //
  986. // Notes:
  987. //
  988. HRESULT
  989. HrSerializeResponse(
  990. IN IUPnPAutomationProxy * pAutomationProxy,
  991. IN UPNP_CONTROL_REQUEST * pucrDeserialized,
  992. IN UPNP_CONTROL_RESPONSE * pucrespDeserialized,
  993. IN IUPnPServiceDescriptionInfo * pServiceDescInfo,
  994. IN UPNP_SOAP_RESPONSE * pusrespSerialized)
  995. {
  996. HRESULT hr = S_OK;
  997. IXMLDOMDocument * pxddResponse = NULL;
  998. IXMLDOMNode * pxdnRespEnvelope = NULL;
  999. // Create an XML DOM Document in which we'll build the XML response.
  1000. hr = CoCreateInstance(CLSID_DOMDocument30,
  1001. NULL,
  1002. CLSCTX_INPROC_SERVER,
  1003. IID_IXMLDOMDocument,
  1004. (void **) &pxddResponse);
  1005. if (SUCCEEDED(hr))
  1006. {
  1007. Assert(pxddResponse);
  1008. hr = HrAppendProcessingInstruction(pxddResponse, L"xml", L"version=\"1.0\"");
  1009. // Create the envelope element.
  1010. if (SUCCEEDED(hr))
  1011. {
  1012. hr = HrCreateElement(pxddResponse,
  1013. L"SOAP-ENV:Envelope",
  1014. WSZ_SOAP_NAMESPACE_URI,
  1015. &pxdnRespEnvelope);
  1016. }
  1017. if (SUCCEEDED(hr))
  1018. {
  1019. Assert(pxdnRespEnvelope);
  1020. IXMLDOMElement * pxdeRespEnvelope = NULL;
  1021. hr = pxdnRespEnvelope->QueryInterface(IID_IXMLDOMElement, (void**)&pxdeRespEnvelope);
  1022. if (SUCCEEDED(hr))
  1023. {
  1024. hr = HrSetTextAttribute(pxdeRespEnvelope, L"SOAP-ENV:encodingStyle",
  1025. L"http://schemas.xmlsoap.org/soap/encoding/");
  1026. pxdeRespEnvelope->Release();
  1027. pxdeRespEnvelope = NULL;
  1028. }
  1029. if (SUCCEEDED(hr))
  1030. {
  1031. IXMLDOMNode * pxdnBody = NULL;
  1032. hr = HrCreateElement(pxddResponse,
  1033. L"SOAP-ENV:Body",
  1034. WSZ_SOAP_NAMESPACE_URI,
  1035. &pxdnBody);
  1036. if (SUCCEEDED(hr))
  1037. {
  1038. Assert(pxdnBody);
  1039. if (pucrespDeserialized->fSucceeded)
  1040. {
  1041. hr = HrAppendActionResponseElementToBody(pAutomationProxy,
  1042. pxddResponse,
  1043. pxdnBody,
  1044. pucrDeserialized,
  1045. pucrespDeserialized,
  1046. pServiceDescInfo);
  1047. if (UPNP_E_DEVICE_ERROR == hr)
  1048. {
  1049. // Failed at the last minute
  1050. // Change our minds and send a fault response
  1051. CleanupResponseData(&pucrespDeserialized->ucrData, TRUE);
  1052. pucrespDeserialized->fSucceeded = FALSE;
  1053. pucrespDeserialized->ucrData.Fault.bstrFaultCode =
  1054. SysAllocString(L"SOAP-ENV:Client");
  1055. pucrespDeserialized->ucrData.Fault.bstrFaultString =
  1056. SysAllocString(L"UPnPError");
  1057. pucrespDeserialized->ucrData.Fault.bstrUPnPErrorCode =
  1058. SysAllocString(L"501");
  1059. pucrespDeserialized->ucrData.Fault.bstrUPnPErrorString =
  1060. SysAllocString(L"Internal Device Error");
  1061. if (NULL == pucrespDeserialized->ucrData.Fault.bstrFaultCode ||
  1062. NULL == pucrespDeserialized->ucrData.Fault.bstrFaultString ||
  1063. NULL == pucrespDeserialized->ucrData.Fault.bstrUPnPErrorCode ||
  1064. NULL == pucrespDeserialized->ucrData.Fault.bstrUPnPErrorString)
  1065. {
  1066. hr = E_OUTOFMEMORY;
  1067. CleanupResponseData(&pucrespDeserialized->ucrData, FALSE);
  1068. }
  1069. else
  1070. {
  1071. hr = S_OK;
  1072. }
  1073. }
  1074. }
  1075. if (SUCCEEDED(hr) && FALSE == pucrespDeserialized->fSucceeded)
  1076. {
  1077. hr = HrAppendFaultElementToBody(pxddResponse,
  1078. pxdnBody,
  1079. pucrespDeserialized);
  1080. }
  1081. if (SUCCEEDED(hr))
  1082. {
  1083. hr = pxdnRespEnvelope->appendChild(pxdnBody,
  1084. NULL);
  1085. }
  1086. pxdnBody->Release();
  1087. }
  1088. else
  1089. {
  1090. TraceError("HrSerializeResponse(): "
  1091. "Failed to create body element",
  1092. hr);
  1093. }
  1094. }
  1095. else
  1096. {
  1097. // we weren't able to create the encodingStyle attribute
  1098. }
  1099. if (SUCCEEDED(hr))
  1100. {
  1101. hr = pxddResponse->appendChild(pxdnRespEnvelope, NULL);
  1102. }
  1103. if (pxdnRespEnvelope)
  1104. {
  1105. pxdnRespEnvelope->Release();
  1106. }
  1107. }
  1108. else
  1109. {
  1110. TraceError("HrSerializeResponse(): "
  1111. "Failed to create envelope element",
  1112. hr);
  1113. }
  1114. }
  1115. if (SUCCEEDED(hr))
  1116. {
  1117. Assert(pxddResponse);
  1118. // Cleanup any old data.
  1119. CleanupSerializedResponse(pusrespSerialized);
  1120. pusrespSerialized->fSucceeded = pucrespDeserialized->fSucceeded;
  1121. pusrespSerialized->pxddRespEnvelope = pxddResponse;
  1122. }
  1123. else
  1124. {
  1125. if (pxddResponse)
  1126. {
  1127. pxddResponse->Release();
  1128. pxddResponse = NULL;
  1129. }
  1130. }
  1131. TraceError("HrSerializeResponse(): "
  1132. "Exiting",
  1133. hr);
  1134. return hr;
  1135. }
  1136. //+---------------------------------------------------------------------------
  1137. //
  1138. // Function: HrExecuteRequest
  1139. //
  1140. // Purpose: Executes a request.
  1141. //
  1142. // Arguments:
  1143. // pAutomationProxy [in] The automation proxy for the target service
  1144. // pucreq [in] Address of the structure containing the
  1145. // deserialized request
  1146. // pucresp [in] Address of the structure whose fields will be
  1147. // initialized with the serialized response info
  1148. //
  1149. // Returns:
  1150. // If the function succeeds, the return value is S_OK. Otherwise, the
  1151. // function returns one of the COM error codes defined in WinError.h.
  1152. //
  1153. // Author: spather 2000/09/24
  1154. //
  1155. // Notes:
  1156. //
  1157. HRESULT
  1158. HrExecuteRequest(
  1159. IN IUPnPAutomationProxy * pAutomationProxy,
  1160. IN UPNP_CONTROL_REQUEST * pucreq,
  1161. IN UPNP_CONTROL_RESPONSE * pucresp)
  1162. {
  1163. HRESULT hr = S_OK;
  1164. hr = pAutomationProxy->ExecuteRequest(pucreq, pucresp);
  1165. if (SUCCEEDED(hr))
  1166. {
  1167. TraceTag(ttidUDHISAPI,
  1168. "HrExecuteRequest(): "
  1169. "IUPnPAutomationProxy::Execute() succeeded");
  1170. }
  1171. else
  1172. {
  1173. TraceError("HrExecuteRequest(): "
  1174. "Failed to execute request",
  1175. hr);
  1176. }
  1177. TraceError("HrExecuteRequest(): "
  1178. "Exiting",
  1179. hr);
  1180. return hr;
  1181. }
  1182. //+---------------------------------------------------------------------------
  1183. //
  1184. // Function: HrDeserializeSOAPRequest
  1185. //
  1186. // Purpose: Deserializes a parsed SOAP Request
  1187. //
  1188. // Arguments:
  1189. // pusrParsed [in] Address of structure containing parsed request
  1190. // pServiceDescInfo [in] Service Description Info object for the service
  1191. // pucrDeserialized [in] Address of structure whose fields will be
  1192. // initialized with the deserialized request info
  1193. //
  1194. // Returns:
  1195. // If the function succeeds, the return value is S_OK. Otherwise, the
  1196. // function returns one of the COM error codes defined in WinError.h.
  1197. //
  1198. // Author: spather 2000/09/24
  1199. //
  1200. // Notes:
  1201. //
  1202. HRESULT
  1203. HrDeserializeSOAPRequest(
  1204. IN UPNP_SOAP_REQUEST * pusrParsed,
  1205. IN IUPnPServiceDescriptionInfo * pServiceDescInfo,
  1206. IN UPNP_CONTROL_REQUEST * pucrDeserialized)
  1207. {
  1208. HRESULT hr = S_OK;
  1209. UPNP_CONTROL_REQUEST ucr;
  1210. BOOL fIsQueryStateVariable = FALSE;
  1211. ZeroMemory(&ucr, sizeof(UPNP_CONTROL_REQUEST));
  1212. // First, copy the action name.
  1213. ucr.bstrActionName = SysAllocString(pusrParsed->bstrActionName);
  1214. if (ucr.bstrActionName)
  1215. {
  1216. if (0 == lstrcmpW(ucr.bstrActionName, L"QueryStateVariable"))
  1217. {
  1218. fIsQueryStateVariable = TRUE;
  1219. }
  1220. // Next, deserialize the arguments, if any.
  1221. if (pusrParsed->pxdnlArgs)
  1222. {
  1223. LONG listLength = 0;
  1224. hr = pusrParsed->pxdnlArgs->get_length(&listLength);
  1225. if (SUCCEEDED(hr))
  1226. {
  1227. if (listLength)
  1228. {
  1229. // Allocate array of VARIANT arguments.
  1230. ucr.cInputArgs = (DWORD) listLength;
  1231. ucr.rgvarInputArgs = new VARIANT[ucr.cInputArgs];
  1232. if (ucr.rgvarInputArgs)
  1233. {
  1234. DWORD cInArgs = 0;
  1235. BSTR * rgbstrNames = NULL;
  1236. BSTR * rgbstrTypes = NULL;
  1237. ZeroMemory(ucr.rgvarInputArgs,
  1238. ucr.cInputArgs * sizeof(VARIANT));
  1239. if (FALSE == fIsQueryStateVariable)
  1240. {
  1241. // Only get the argument names and types if this is
  1242. // not a QSV request. For a QSV request, there is
  1243. // only one argument (the variable name) and it's
  1244. // type is "string".
  1245. hr = pServiceDescInfo->GetInputArgumentNamesAndTypes(ucr.bstrActionName,
  1246. &cInArgs,
  1247. &rgbstrNames,
  1248. &rgbstrTypes);
  1249. if (SUCCEEDED(hr))
  1250. {
  1251. Assert(cInArgs == ucr.cInputArgs);
  1252. Assert(rgbstrNames);
  1253. Assert(rgbstrTypes);
  1254. }
  1255. }
  1256. if (SUCCEEDED(hr))
  1257. {
  1258. // For each argument node, get the value and put it into
  1259. // the variant array.
  1260. for (LONG i = 0; SUCCEEDED(hr) && (i < listLength); i++)
  1261. {
  1262. IXMLDOMNode * pxdnItem = NULL;
  1263. hr = pusrParsed->pxdnlArgs->get_item(i, &pxdnItem);
  1264. if (SUCCEEDED(hr))
  1265. {
  1266. if (fIsQueryStateVariable)
  1267. {
  1268. BSTR * pbstr = &(V_BSTR(&ucr.rgvarInputArgs[i]));
  1269. hr = pxdnItem->get_text(pbstr);
  1270. if (SUCCEEDED(hr))
  1271. {
  1272. Assert(*pbstr);
  1273. ucr.rgvarInputArgs[i].vt = VT_BSTR;
  1274. TraceTag(ttidUDHISAPI,
  1275. "HrDeserializeSOAPRequest(): "
  1276. "Got variable name for QSV request: %S",
  1277. *pbstr);
  1278. }
  1279. else
  1280. {
  1281. TraceError("HrDeserializeSOAPRequest(): "
  1282. "Failed to get variable name for QSV request",
  1283. hr);
  1284. }
  1285. }
  1286. else
  1287. {
  1288. hr = HrGetTypedValueFromElement(pxdnItem,
  1289. rgbstrTypes[i],
  1290. &ucr.rgvarInputArgs[i]);
  1291. if (SUCCEEDED(hr))
  1292. {
  1293. TraceTag(ttidUDHISAPI,
  1294. "HrDeserializeSOAPRequest(): "
  1295. "Deserialized argument %S",
  1296. rgbstrNames[i]);
  1297. }
  1298. else
  1299. {
  1300. TraceError("HrDeserializeSOAPRequest(): "
  1301. "Failed to get node value",
  1302. hr);
  1303. }
  1304. }
  1305. pxdnItem->Release();
  1306. }
  1307. else
  1308. {
  1309. TraceError("HrDeserializeSOAPRequest(): "
  1310. "Failed to get item from list",
  1311. hr);
  1312. }
  1313. }
  1314. if (FALSE == fIsQueryStateVariable)
  1315. {
  1316. // Only got this stuff if it was not a QSV
  1317. // request, so only clean it up in this case.
  1318. for (DWORD i = 0; i < cInArgs; i++)
  1319. {
  1320. SysFreeString(rgbstrNames[i]);
  1321. rgbstrNames[i] = NULL;
  1322. SysFreeString(rgbstrTypes[i]);
  1323. rgbstrTypes[i] = NULL;
  1324. }
  1325. CoTaskMemFree(rgbstrNames);
  1326. rgbstrNames = NULL;
  1327. CoTaskMemFree(rgbstrTypes);
  1328. rgbstrTypes = NULL;
  1329. }
  1330. }
  1331. }
  1332. else
  1333. {
  1334. hr = E_OUTOFMEMORY;
  1335. TraceError("HrDeserializeSOAPRequest(): "
  1336. "Failed to allocate array of variant arguments",
  1337. hr);
  1338. }
  1339. }
  1340. else
  1341. {
  1342. ucr.cInputArgs = 0;
  1343. ucr.rgvarInputArgs = NULL;
  1344. }
  1345. }
  1346. else
  1347. {
  1348. TraceError("HrDeserializeSOAPRequest(): "
  1349. "Failed to get argument list length",
  1350. hr);
  1351. }
  1352. }
  1353. else
  1354. {
  1355. ucr.cInputArgs = 0;
  1356. ucr.rgvarInputArgs = NULL;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. hr = E_OUTOFMEMORY;
  1362. TraceError("HrDeserializeSOAPRequest(): "
  1363. "Failed to allocate memory to copy action name",
  1364. hr);
  1365. }
  1366. if (SUCCEEDED(hr))
  1367. {
  1368. Assert(ucr.bstrActionName);
  1369. Assert(FImplies((ucr.cInputArgs > 0), ucr.rgvarInputArgs));
  1370. Assert(FImplies((0 == ucr.cInputArgs), (NULL == ucr.rgvarInputArgs)));
  1371. // Clean up any existing data in the output structure.
  1372. CleanupDeserializedRequest(pucrDeserialized);
  1373. pucrDeserialized->bstrActionName = ucr.bstrActionName;
  1374. pucrDeserialized->cInputArgs = ucr.cInputArgs;
  1375. pucrDeserialized->rgvarInputArgs = ucr.rgvarInputArgs;
  1376. }
  1377. else
  1378. {
  1379. // Clean up.
  1380. CleanupDeserializedRequest(&ucr);
  1381. }
  1382. TraceError("HrDeserializeSOAPRequest(): "
  1383. "Exiting",
  1384. hr);
  1385. return hr;
  1386. }
  1387. //+---------------------------------------------------------------------------
  1388. //
  1389. // Function: HrParseSOAPRequest
  1390. //
  1391. // Purpose: Parses a SOAP request and returns the parsed action name
  1392. // and list of arguments.
  1393. //
  1394. // Arguments:
  1395. // pxdnReqEnvelope [in] XML DOM node representing the SOAP envelope
  1396. // pusrParsed [in] Address of a UPNP_SOAP_REQUEST structure whose
  1397. // fields will be initialized with the parsed info
  1398. // Returns:
  1399. // If the function succeeds, the return value is S_OK. Otherwise, the
  1400. // function returns one of the COM error codes defined in WinError.h.
  1401. //
  1402. // Author: spather 2000/09/24
  1403. //
  1404. // Notes:
  1405. //
  1406. HRESULT
  1407. HrParseSOAPRequest(
  1408. IN IXMLDOMNode * pxdnReqEnvelope,
  1409. IN UPNP_SOAP_REQUEST * pusrParsed)
  1410. {
  1411. HRESULT hr = S_OK;
  1412. IXMLDOMNode * pxdnBody = NULL;
  1413. LPWSTR rgpszBodyTokens[] = {L"Body"};
  1414. BSTR bstrActionName = NULL;
  1415. IXMLDOMNodeList * pxdnlArgs = NULL;
  1416. hr = HrGetNestedChildElement(pxdnReqEnvelope,
  1417. rgpszBodyTokens,
  1418. 1,
  1419. &pxdnBody);
  1420. if (S_OK == hr)
  1421. {
  1422. IXMLDOMNode * pxdnAction = NULL;
  1423. Assert(pxdnBody);
  1424. hr = pxdnBody->get_firstChild(&pxdnAction);
  1425. if (S_OK == hr)
  1426. {
  1427. Assert(pxdnAction);
  1428. hr = pxdnAction->get_baseName(&bstrActionName);
  1429. if (SUCCEEDED(hr))
  1430. {
  1431. Assert(bstrActionName);
  1432. hr = pxdnAction->get_childNodes(&pxdnlArgs);
  1433. if (SUCCEEDED(hr))
  1434. {
  1435. TraceTag(ttidUDHISAPI,
  1436. "HrParseSOAPRequest(): "
  1437. "Successfully obtained name and argument list "
  1438. "for action %S\n",
  1439. bstrActionName);
  1440. }
  1441. else
  1442. {
  1443. TraceError("HrParseSOAPRequest(): "
  1444. "Failed to get argument list",
  1445. hr);
  1446. }
  1447. }
  1448. else
  1449. {
  1450. TraceError("HrParseSOAPRequest(): "
  1451. "Failed to get action name",
  1452. hr);
  1453. }
  1454. pxdnAction->Release();
  1455. }
  1456. else
  1457. {
  1458. TraceError("HrParseSOAPRequest(): "
  1459. "Failed to get action element",
  1460. hr);
  1461. if (S_FALSE == hr)
  1462. {
  1463. hr = E_FAIL;
  1464. }
  1465. }
  1466. pxdnBody->Release();
  1467. }
  1468. else
  1469. {
  1470. TraceError("HrParseSOAPRequest(): "
  1471. "Failed to get Body element",
  1472. hr);
  1473. if (S_FALSE == hr)
  1474. {
  1475. hr = E_FAIL;
  1476. }
  1477. }
  1478. if (SUCCEEDED(hr))
  1479. {
  1480. // Clean up any existing data in the output strucutre.
  1481. CleanupSerializedRequest(pusrParsed);
  1482. pusrParsed->bstrActionName = bstrActionName;
  1483. pusrParsed->pxdnlArgs = pxdnlArgs;
  1484. }
  1485. else
  1486. {
  1487. // Cleanup
  1488. if (bstrActionName)
  1489. {
  1490. SysFreeString(bstrActionName);
  1491. bstrActionName = NULL;
  1492. }
  1493. if (pxdnlArgs)
  1494. {
  1495. pxdnlArgs->Release();
  1496. pxdnlArgs = NULL;
  1497. }
  1498. // any error other than E_OUTOFMEMORY implies bad SOAP
  1499. if (hr != E_OUTOFMEMORY)
  1500. {
  1501. hr = UPNP_E_BAD_REQUEST;
  1502. }
  1503. }
  1504. TraceError("HrParseSOAPRequest(): "
  1505. "Exiting",
  1506. hr);
  1507. return hr;
  1508. }
  1509. //+---------------------------------------------------------------------------
  1510. //
  1511. // Function: HrValidateControlRequest
  1512. //
  1513. // Purpose: Validates the structure and content of a control request
  1514. //
  1515. // Arguments:
  1516. // pecb [in] The extension control block for the request
  1517. // pxdnReqEnvelope [in] The request envelope
  1518. // pServiceDescInfo[in] The service description info object for the
  1519. // service
  1520. //
  1521. // Returns:
  1522. // If the function succeeds, the return value is S_OK. Otherwise, the
  1523. // function returns one of the COM error codes defined in WinError.h.
  1524. //
  1525. // Author: spather 2000/09/25
  1526. //
  1527. // Notes:
  1528. //
  1529. HRESULT HrValidateControlRequest(
  1530. IN LPEXTENSION_CONTROL_BLOCK pecb,
  1531. IN IXMLDOMNode * pxdnReqEnvelope,
  1532. IN IUPnPServiceDescriptionInfo * pServiceDescInfo)
  1533. {
  1534. HRESULT hr = S_OK;
  1535. hr = HrValidateSOAPRequest(pxdnReqEnvelope,
  1536. pecb,
  1537. pServiceDescInfo);
  1538. TraceError("HrValidateRequest(): "
  1539. "Exiting",
  1540. hr);
  1541. return hr;
  1542. }
  1543. //+---------------------------------------------------------------------------
  1544. //
  1545. // Function: HrReadRequest
  1546. //
  1547. // Purpose: Reads the HTTP packet body of a control request, loads
  1548. // it into an XML DOM document, validates it for correctness,
  1549. // and, if valid, returns a pointer to the XML DOM node
  1550. // representing the request envelope.
  1551. //
  1552. // Arguments:
  1553. // pecb [in] The extension control block for the request.
  1554. // ppxdnReqEnvelope [out] Receives a pointer to the XML DOM node
  1555. // representing the request envelope.
  1556. //
  1557. // Returns:
  1558. // If the function succeeds, the return value is S_OK. Otherwise, the
  1559. // function returns one of the COM error codes defined in WinError.h.
  1560. //
  1561. // Author: spather 2000/09/24
  1562. //
  1563. // Notes:
  1564. //
  1565. HRESULT
  1566. HrReadRequest(
  1567. IN LPEXTENSION_CONTROL_BLOCK pecb,
  1568. OUT IXMLDOMNode ** ppxdnReqEnvelope)
  1569. {
  1570. HRESULT hr = S_OK;
  1571. DWORD cbReqBody = 0;
  1572. LPSTR pszaReqBody = NULL;
  1573. BSTR bstrReqBody = NULL;
  1574. // Get the request body. If it's not all here, read it in.
  1575. if (pecb->cbAvailable < pecb->cbTotalBytes)
  1576. {
  1577. // There is some data that is not available in the extension
  1578. // control block. Read it from the client.
  1579. cbReqBody = pecb->cbTotalBytes;
  1580. pszaReqBody = new CHAR[cbReqBody];
  1581. if (pszaReqBody)
  1582. {
  1583. DWORD cbBytesToRead = cbReqBody;
  1584. DWORD cbBytesRead = 0;
  1585. LPSTR pszaTemp = pszaReqBody;
  1586. while (cbBytesRead < cbReqBody)
  1587. {
  1588. if (pecb->ReadClient(pecb->ConnID,
  1589. pszaTemp,
  1590. &cbBytesToRead))
  1591. {
  1592. // After calling ReadClient, cbBytesToRead contains the
  1593. // number of bytes actually read.
  1594. cbBytesRead += cbBytesToRead;
  1595. pszaTemp += cbBytesToRead;
  1596. cbBytesToRead = cbReqBody - cbBytesRead;
  1597. }
  1598. else
  1599. {
  1600. TraceLastWin32Error("HrReadRequest(): "
  1601. "ReadClient() failed");
  1602. hr = HrFromLastWin32Error();
  1603. break;
  1604. }
  1605. }
  1606. }
  1607. else
  1608. {
  1609. hr = E_OUTOFMEMORY;
  1610. TraceError("HrReadRequest(): "
  1611. "Could not allocate memory for request body",
  1612. hr);
  1613. }
  1614. }
  1615. else
  1616. {
  1617. cbReqBody = pecb->cbAvailable;
  1618. pszaReqBody = (LPSTR) pecb->lpbData;
  1619. if (0 == cbReqBody)
  1620. {
  1621. // There is no body in the request.
  1622. hr = UPNP_E_MISSING_CONTENT_LENGTH;
  1623. TraceError("HrReadRequest(): "
  1624. "Request had no body",
  1625. hr);
  1626. }
  1627. }
  1628. // Turn the request body into a BSTR.
  1629. if (SUCCEEDED(hr))
  1630. {
  1631. INT result = 0;
  1632. INT cchWide = 0;
  1633. Assert(pszaReqBody);
  1634. // Have to convert the request body into a BSTR to load it into
  1635. // an XML DOM document.
  1636. result = MultiByteToWideChar(CP_UTF8,
  1637. 0,
  1638. pszaReqBody,
  1639. cbReqBody,
  1640. NULL,
  1641. 0);
  1642. if (result)
  1643. {
  1644. LPWSTR pszBody = NULL;
  1645. cchWide = result;
  1646. pszBody = new WCHAR[cchWide+1]; // want NULL termination
  1647. if (pszBody)
  1648. {
  1649. result = MultiByteToWideChar(CP_UTF8,
  1650. 0,
  1651. pszaReqBody,
  1652. cbReqBody,
  1653. pszBody,
  1654. cchWide);
  1655. if (result)
  1656. {
  1657. pszBody[cchWide] = UNICODE_NULL;
  1658. bstrReqBody = SysAllocString(pszBody);
  1659. if (bstrReqBody)
  1660. {
  1661. TraceTag(ttidUDHISAPI,
  1662. "HrReadRequest(): "
  1663. "Request Body is \n%S",
  1664. bstrReqBody);
  1665. }
  1666. else
  1667. {
  1668. hr = E_OUTOFMEMORY;
  1669. TraceError("HrReadRequest(): "
  1670. "Failed to allocate BSTR request body",
  1671. hr);
  1672. }
  1673. }
  1674. else
  1675. {
  1676. TraceLastWin32Error("HrReadRequest(): "
  1677. "MultiByteToWideChar #2 failed");
  1678. hr = HrFromLastWin32Error();
  1679. }
  1680. delete [] pszBody;
  1681. pszBody = NULL;
  1682. }
  1683. else
  1684. {
  1685. hr = E_OUTOFMEMORY;
  1686. TraceError("HrReadRequest(): "
  1687. "Failed to allocate memory for wide char body",
  1688. hr);
  1689. }
  1690. }
  1691. else
  1692. {
  1693. TraceLastWin32Error("HrReadRequest(): "
  1694. "MultiByteToWideChar #1 failed");
  1695. hr = HrFromLastWin32Error();
  1696. }
  1697. }
  1698. // Create an XML DOM document from the request body.
  1699. if (SUCCEEDED(hr))
  1700. {
  1701. IXMLDOMDocument * pxddRequest = NULL;
  1702. hr = CoCreateInstance(CLSID_DOMDocument30,
  1703. NULL,
  1704. CLSCTX_INPROC_SERVER,
  1705. IID_IXMLDOMDocument,
  1706. (void **) &pxddRequest);
  1707. if (SUCCEEDED(hr))
  1708. {
  1709. Assert(pxddRequest);
  1710. hr = pxddRequest->put_async(VARIANT_FALSE);
  1711. if (SUCCEEDED(hr))
  1712. {
  1713. VARIANT_BOOL vbSuccess = VARIANT_FALSE;
  1714. hr = HrValidateContentType(pecb);
  1715. if (SUCCEEDED(hr))
  1716. {
  1717. pxddRequest->put_resolveExternals(VARIANT_FALSE);
  1718. hr = pxddRequest->loadXML(bstrReqBody, &vbSuccess);
  1719. }
  1720. if (SUCCEEDED(hr) && (VARIANT_TRUE == vbSuccess))
  1721. {
  1722. IXMLDOMElement * pxdeEnvelope = NULL;
  1723. hr = pxddRequest->get_documentElement(&pxdeEnvelope);
  1724. if (S_OK == hr)
  1725. {
  1726. Assert(pxdeEnvelope);
  1727. hr = pxdeEnvelope->QueryInterface(IID_IXMLDOMNode,
  1728. (void **)
  1729. ppxdnReqEnvelope);
  1730. if (SUCCEEDED(hr))
  1731. {
  1732. TraceTag(ttidUDHISAPI,
  1733. "HrReadRequest(): "
  1734. "Successfully obtained XML DOM Node for "
  1735. "request envelope");
  1736. }
  1737. else
  1738. {
  1739. TraceError("HrReadRequest(): "
  1740. "Failed to QI for IXMLDOMNode",
  1741. hr);
  1742. }
  1743. pxdeEnvelope->Release();
  1744. }
  1745. else
  1746. {
  1747. TraceError("HrReadRequest(): "
  1748. "Failed to get document element",
  1749. hr);
  1750. }
  1751. }
  1752. else
  1753. {
  1754. if (S_FALSE == hr)
  1755. {
  1756. // There was a parse error.
  1757. Assert(VARIANT_FALSE == vbSuccess);
  1758. hr = UPNP_E_BAD_REQUEST;
  1759. }
  1760. TraceError("HrReadRequest(): "
  1761. "Failed to load XML",
  1762. hr);
  1763. }
  1764. }
  1765. else
  1766. {
  1767. TraceError("HrReadRequest(): "
  1768. "Failed to set async property on DOM document",
  1769. hr);
  1770. }
  1771. pxddRequest->Release();
  1772. }
  1773. else
  1774. {
  1775. TraceError("HrReadRequest(): "
  1776. "Failed to create XML DOM document",
  1777. hr);
  1778. }
  1779. }
  1780. // Cleanup
  1781. if (bstrReqBody)
  1782. {
  1783. SysFreeString(bstrReqBody);
  1784. bstrReqBody = NULL;
  1785. }
  1786. if (pszaReqBody && (pszaReqBody != (LPSTR)pecb->lpbData))
  1787. {
  1788. delete [] pszaReqBody;
  1789. pszaReqBody = NULL;
  1790. cbReqBody = 0;
  1791. }
  1792. TraceError("HrReadRequest(): "
  1793. "Exiting",
  1794. hr);
  1795. return hr;
  1796. }
  1797. //+---------------------------------------------------------------------------
  1798. //
  1799. // Function: HrParseControlQueryString
  1800. //
  1801. // Purpose: Parses the query string to a control request and uses
  1802. // the registrar to obtain the Automation Proxy object for
  1803. // the service specified in it.
  1804. //
  1805. // Arguments:
  1806. // pszaQueryString [in] The query string.
  1807. // ppAutomationProxy [out] Receives a pointer to the Automation Proxy
  1808. // object for the service
  1809. //
  1810. // Returns:
  1811. // If the function succeeds, the return value is S_OK. Otherwise, the
  1812. // function returns one of the COM error codes defined in WinError.h.
  1813. //
  1814. // Author: spather 2000/09/25
  1815. //
  1816. // Notes:
  1817. //
  1818. HRESULT HrParseControlQueryString(
  1819. IN LPSTR pszaQueryString,
  1820. OUT IUPnPAutomationProxy ** ppAutomationProxy)
  1821. {
  1822. HRESULT hr = S_OK;
  1823. DWORD cchQueryString = 0;
  1824. DWORD cchPrefix = 0;
  1825. LPCSTR pcszaPrefix = "control=";
  1826. LPWSTR pszUDN = NULL;
  1827. LPWSTR pszServiceID = NULL;
  1828. // Control query string is of the form:
  1829. // control=UDN+ServiceID.
  1830. // We know that at least the word "control" is there because
  1831. // that main dispatch code that called us already checked for it.
  1832. cchPrefix = lstrlenA(pcszaPrefix);
  1833. cchQueryString = lstrlenA(pszaQueryString);
  1834. if (cchQueryString > cchPrefix)
  1835. {
  1836. LPSTR pszaUDNStart = NULL;
  1837. LPSTR pszaDelimiter = NULL;
  1838. pszaUDNStart = pszaQueryString+cchPrefix;
  1839. for (DWORD i = cchPrefix; i < cchQueryString; i++)
  1840. {
  1841. if ('+' == pszaQueryString[i])
  1842. {
  1843. pszaDelimiter = &pszaQueryString[i];
  1844. break;
  1845. }
  1846. }
  1847. if (pszaDelimiter)
  1848. {
  1849. DWORD cchUDN = (DWORD) (pszaDelimiter - pszaUDNStart);
  1850. LPSTR pszaUDN = NULL;
  1851. pszaUDN = new CHAR[cchUDN+1];
  1852. if (pszaUDN)
  1853. {
  1854. LPSTR pszaServiceID = NULL;
  1855. lstrcpynA(pszaUDN, pszaUDNStart, cchUDN+1);
  1856. pszaServiceID = pszaDelimiter+1;
  1857. if (*pszaServiceID)
  1858. {
  1859. pszUDN = WszFromSz(pszaUDN);
  1860. if (pszUDN)
  1861. {
  1862. pszServiceID = WszFromSz(pszaServiceID);
  1863. if (pszServiceID)
  1864. {
  1865. TraceTag(ttidUDHISAPI,
  1866. "HrParseControlRequest(): "
  1867. "UDN == %S and ServiceID == %S",
  1868. pszUDN,
  1869. pszServiceID);
  1870. }
  1871. else
  1872. {
  1873. hr = E_OUTOFMEMORY;
  1874. TraceError("HrParseControlQueryString(): "
  1875. "Failed to convert Service ID to "
  1876. "unicode string",
  1877. hr);
  1878. }
  1879. }
  1880. else
  1881. {
  1882. hr = E_OUTOFMEMORY;
  1883. TraceError("HrParseControlQueryString(): "
  1884. "Failed to convert UDN to unicode string",
  1885. hr);
  1886. }
  1887. }
  1888. else
  1889. {
  1890. hr = E_INVALIDARG;
  1891. TraceError("HrParseControlQueryString(): "
  1892. "No service ID found",
  1893. hr);
  1894. }
  1895. delete [] pszaUDN;
  1896. pszaUDN = NULL;
  1897. }
  1898. else
  1899. {
  1900. hr = E_OUTOFMEMORY;
  1901. TraceError("HrParseControlQueryString(): "
  1902. "Failed to allocate memory for UDN ANSI string",
  1903. hr);
  1904. }
  1905. }
  1906. else
  1907. {
  1908. hr = E_INVALIDARG;
  1909. TraceError("HrParseControlQueryString(): "
  1910. "Could not find delimiter character",
  1911. hr);
  1912. }
  1913. }
  1914. else
  1915. {
  1916. hr = E_INVALIDARG;
  1917. TraceError("HrParseControlQueryString(): "
  1918. "Length of query string was <= length of the prefix",
  1919. hr);
  1920. }
  1921. // If the above succeeded, we should have the UDN and service ID
  1922. // as wide strings.
  1923. if (SUCCEEDED(hr))
  1924. {
  1925. IUPnPRegistrarLookup * pRegistrarLookup = NULL;
  1926. hr = CoCreateInstance(CLSID_UPnPRegistrar,
  1927. NULL,
  1928. CLSCTX_INPROC_SERVER,
  1929. IID_IUPnPRegistrarLookup,
  1930. (void **) &pRegistrarLookup);
  1931. if (SUCCEEDED(hr))
  1932. {
  1933. hr = pRegistrarLookup->GetAutomationProxy(pszUDN,
  1934. pszServiceID,
  1935. ppAutomationProxy);
  1936. if (SUCCEEDED(hr))
  1937. {
  1938. TraceTag(ttidUDHISAPI,
  1939. "HrParseControlQuerySring(): "
  1940. "Successfully obtained automation proxy");
  1941. }
  1942. else
  1943. {
  1944. TraceError("HrParseControlQueryString(): "
  1945. "Failed to get automation proxy",
  1946. hr);
  1947. }
  1948. pRegistrarLookup->Release();
  1949. }
  1950. else
  1951. {
  1952. TraceError("HrParseControlQueryString(): "
  1953. "Failed to create registrar object",
  1954. hr);
  1955. }
  1956. }
  1957. // Cleanup
  1958. if (pszUDN)
  1959. {
  1960. delete [] pszUDN;
  1961. pszUDN = NULL;
  1962. }
  1963. if (pszServiceID)
  1964. {
  1965. delete [] pszServiceID;
  1966. pszServiceID = NULL;
  1967. }
  1968. TraceError("HrParseControlQueryString(): "
  1969. "Exiting",
  1970. hr);
  1971. return hr;
  1972. }
  1973. //+---------------------------------------------------------------------------
  1974. //
  1975. // Function: HrDoRequestAndReturnResponse
  1976. //
  1977. // Purpose: This function does the main work in processing a control
  1978. // request. It reads the request, parses it, deserializes it,
  1979. // executes it, serializes the response, generates a SOAP
  1980. // response and sends that to the client.
  1981. //
  1982. // Arguments:
  1983. // pecb [in] The extension control block for the request.
  1984. //
  1985. // Returns:
  1986. // If the function succeeds, the return value is S_OK. Otherwise, the
  1987. // function returns one of the COM error codes defined in WinError.h.
  1988. //
  1989. // Author: spather 2000/09/24
  1990. //
  1991. // Notes:
  1992. //
  1993. HRESULT
  1994. HrDoRequestAndReturnResponse(
  1995. IN LPEXTENSION_CONTROL_BLOCK pecb)
  1996. {
  1997. HRESULT hr = S_OK;
  1998. IXMLDOMNode * pxdnReqEnvelope = NULL;
  1999. IUPnPAutomationProxy * pAutomationProxy = NULL;
  2000. IUPnPServiceDescriptionInfo * pServiceDescriptionInfo = NULL;
  2001. // At this point, we do not know if the request is valid. First we'll
  2002. // parse the query string, use the registrar to look up the service it
  2003. // specifies. If this succeeeds, we'll read the request body, and validate
  2004. // its structure.
  2005. hr = HrParseControlQueryString(pecb->lpszQueryString,
  2006. &pAutomationProxy);
  2007. if (SUCCEEDED(hr))
  2008. {
  2009. Assert(pAutomationProxy);
  2010. hr = pAutomationProxy->QueryInterface(IID_IUPnPServiceDescriptionInfo,
  2011. (void **) &pServiceDescriptionInfo);
  2012. if (SUCCEEDED(hr))
  2013. {
  2014. Assert(pServiceDescriptionInfo);
  2015. hr = HrReadRequest(pecb, &pxdnReqEnvelope);
  2016. if (SUCCEEDED(hr))
  2017. {
  2018. hr = HrValidateControlRequest(pecb,
  2019. pxdnReqEnvelope,
  2020. pServiceDescriptionInfo);
  2021. }
  2022. }
  2023. else
  2024. {
  2025. TraceError("HrDoRequestAndReturnResponse(): "
  2026. "Failed to get service desc info interface",
  2027. hr);
  2028. }
  2029. }
  2030. // If everything above succeeded, we can assume the request is
  2031. // completely valid.
  2032. if (SUCCEEDED(hr))
  2033. {
  2034. UPNP_SOAP_REQUEST usrParsed;
  2035. Assert(pxdnReqEnvelope);
  2036. ZeroMemory(&usrParsed, sizeof(UPNP_SOAP_REQUEST));
  2037. hr = HrParseSOAPRequest(pxdnReqEnvelope, &usrParsed);
  2038. if (SUCCEEDED(hr))
  2039. {
  2040. UPNP_CONTROL_REQUEST ucrDeserialized;
  2041. ZeroMemory(&ucrDeserialized, sizeof(UPNP_CONTROL_REQUEST));
  2042. hr = HrDeserializeSOAPRequest(&usrParsed,
  2043. pServiceDescriptionInfo,
  2044. &ucrDeserialized);
  2045. if (SUCCEEDED(hr))
  2046. {
  2047. UPNP_CONTROL_RESPONSE ucrespDeserialized;
  2048. ZeroMemory(&ucrespDeserialized, sizeof(UPNP_CONTROL_RESPONSE));
  2049. hr = HrExecuteRequest(pAutomationProxy,
  2050. &ucrDeserialized,
  2051. &ucrespDeserialized);
  2052. if (SUCCEEDED(hr))
  2053. {
  2054. UPNP_SOAP_RESPONSE usrespSerialized = {0};
  2055. hr = HrSerializeResponse(pAutomationProxy,
  2056. &ucrDeserialized,
  2057. &ucrespDeserialized,
  2058. pServiceDescriptionInfo,
  2059. &usrespSerialized);
  2060. if (SUCCEEDED(hr))
  2061. {
  2062. Assert(usrespSerialized.pxddRespEnvelope);
  2063. hr = HrWriteResponse(pecb,
  2064. usrespSerialized.pxddRespEnvelope,
  2065. usrespSerialized.fSucceeded);
  2066. CleanupSerializedResponse(&usrespSerialized);
  2067. }
  2068. CleanupDeserializedResponse(&ucrespDeserialized);
  2069. }
  2070. CleanupDeserializedRequest(&ucrDeserialized);
  2071. }
  2072. CleanupSerializedRequest(&usrParsed);
  2073. }
  2074. }
  2075. // Cleanup
  2076. if (pServiceDescriptionInfo)
  2077. {
  2078. pServiceDescriptionInfo->Release();
  2079. pServiceDescriptionInfo = NULL;
  2080. }
  2081. if (pAutomationProxy)
  2082. {
  2083. pAutomationProxy->Release();
  2084. pAutomationProxy = NULL;
  2085. }
  2086. if (pxdnReqEnvelope)
  2087. {
  2088. pxdnReqEnvelope->Release();
  2089. pxdnReqEnvelope = NULL;
  2090. }
  2091. TraceError("HrDoRequestAndReturnResponse(): "
  2092. "Exiting",
  2093. hr);
  2094. return hr;
  2095. }
  2096. DWORD WINAPI
  2097. DwHandleControlRequest(
  2098. LPVOID lpParameter)
  2099. {
  2100. LPEXTENSION_CONTROL_BLOCK pecb = NULL;
  2101. DWORD dwStatus = HSE_STATUS_SUCCESS;
  2102. HCONN ConnID;
  2103. HRESULT hr = S_OK;
  2104. BOOL fKeepConn = FALSE;
  2105. pecb = (LPEXTENSION_CONTROL_BLOCK) lpParameter;
  2106. AssertSz(pecb,
  2107. "DwHandleControlRequest(): "
  2108. "NULL extension control block");
  2109. pecb->ServerSupportFunction(
  2110. pecb->ConnID,
  2111. HSE_REQ_IS_KEEP_CONN,
  2112. &fKeepConn,
  2113. NULL,
  2114. NULL);
  2115. if(fKeepConn)
  2116. dwStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  2117. else
  2118. dwStatus = HSE_STATUS_SUCCESS;
  2119. ConnID = pecb->ConnID;
  2120. AssertSz(pecb->lpszQueryString,
  2121. "DwHandleControlRequest(): "
  2122. "NULL query string passed");
  2123. // Validate the method.
  2124. hr = HrValidateControlMethod(pecb->lpszMethod);
  2125. if (SUCCEEDED(hr))
  2126. {
  2127. // Get the content GUID.
  2128. TraceTag(ttidUDHISAPI,
  2129. "DwHandleControlRequest(): ConnID(0x%x) "
  2130. "Query string is %s",
  2131. ConnID,
  2132. pecb->lpszQueryString);
  2133. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  2134. if (SUCCEEDED(hr))
  2135. {
  2136. hr = HrDoRequestAndReturnResponse(pecb);
  2137. CoUninitialize();
  2138. }
  2139. else
  2140. {
  2141. TraceTag(ttidUDHISAPI,
  2142. "DwHandleControlRequest(): ConnID(0x%x): "
  2143. "Failed to initialize COM, HRESULT == 0x%x",
  2144. ConnID,
  2145. hr);
  2146. }
  2147. }
  2148. else
  2149. {
  2150. TraceTag(ttidUDHISAPI,
  2151. "DwHandleControlRequest(): ConnID(0x%x): "
  2152. "Failed to validate method %s, HRESULT == 0x%x",
  2153. ConnID,
  2154. pecb->lpszMethod,
  2155. hr);
  2156. }
  2157. if (FAILED(hr))
  2158. {
  2159. if (UPNP_E_MISSING_SOAP_ACTION == hr || UPNP_E_MISSING_CONTENT_LENGTH == hr)
  2160. {
  2161. // these errors result in the less specific error:
  2162. hr = UPNP_E_BAD_REQUEST;
  2163. }
  2164. if (UPNP_E_INVALID_CONTENT_TYPE == hr)
  2165. {
  2166. SendSimpleResponse(pecb, HTTP_STATUS_UNSUPPORTED_MEDIA);
  2167. }
  2168. else if (UPNP_E_BAD_REQUEST == hr)
  2169. {
  2170. SendSimpleResponse(pecb, HTTP_STATUS_BAD_REQUEST);
  2171. }
  2172. else if (UPNP_E_METHOD_NOT_IMPLEMENTED == hr)
  2173. {
  2174. SendSimpleResponse(pecb, HTTP_STATUS_NOT_SUPPORTED);
  2175. }
  2176. else if (UPNP_E_METHOD_NOT_ALLOWED == hr)
  2177. {
  2178. LPCSTR pcszErrorHeaders = "Allow: POST, M-POST\r\n\r\n";
  2179. if (bSendResponseToClient(pecb,
  2180. "405 Method Not Allowed",
  2181. lstrlenA(pcszErrorHeaders),
  2182. pcszErrorHeaders,
  2183. 0,
  2184. NULL))
  2185. {
  2186. pecb->dwHttpStatusCode = HTTP_STATUS_BAD_METHOD;
  2187. }
  2188. }
  2189. else
  2190. {
  2191. LPCSTR pcszErrorHeaders = "\r\n";
  2192. dwStatus = HSE_STATUS_ERROR;
  2193. if (bSendResponseToClient(pecb,
  2194. "500 Internal Server Error",
  2195. lstrlenA(pcszErrorHeaders),
  2196. pcszErrorHeaders,
  2197. 0,
  2198. NULL))
  2199. {
  2200. pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  2201. }
  2202. }
  2203. }
  2204. return dwStatus;
  2205. }