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.

1235 lines
32 KiB

  1. /*++
  2. Copyright (c) 1999 - 2000 Microsoft Corporation
  3. Module Name:
  4. parser.c
  5. Abstract:
  6. This module encode and decode ssdp notify and search messages.
  7. Author:
  8. Ting Cai (tingcai) creation-date-07-25-99
  9. --*/
  10. /* Note:
  11. Use midl memory routines for SSDP_REQUEST
  12. */
  13. #include <pch.h>
  14. #pragma hdrstop
  15. #include "ssdpparserp.h"
  16. #include "ssdpapi.h"
  17. #include "limits.h"
  18. #include "ncstring.h"
  19. #define HTTP_VERSION "HTTP/1.1"
  20. #define END_HEADERS_SIZE 3
  21. const char * szEndOfHeaders = "\n\r\n";
  22. #define HEADER_END_SIZE 4
  23. const char * szHeaderEnd = "\r\n\r\n";
  24. BOOL IsStrDigits(LPSTR pszStr);
  25. VOID strtrim(CHAR ** pszStr);
  26. static const CHAR c_szMaxAge[] = "max-age";
  27. static const DWORD c_cchMaxAge = celems(c_szMaxAge) - 1;
  28. // Keep in sync with SSDP_METHOD in ssdp.idl
  29. CHAR *SsdpMethodStr[] =
  30. {
  31. "NOTIFY",
  32. "M-SEARCH",
  33. "SUBSCRIBE",
  34. "UNSUBSCRIBE",
  35. "INVALID",
  36. };
  37. // Keep in sync with SSDP_HEADER in ssdp.idl
  38. CHAR *SsdpHeaderStr[] =
  39. {
  40. "Host",
  41. "NT",
  42. "NTS",
  43. "ST",
  44. "Man",
  45. "MX",
  46. "Location",
  47. "AL",
  48. "USN",
  49. "Cache-Control",
  50. "Callback",
  51. "Timeout",
  52. "Scope",
  53. "SID",
  54. "SEQ",
  55. "Content-Length",
  56. "Content-Type",
  57. "Server",
  58. "Ext",
  59. };
  60. /*
  61. NOTIFY * HTTP/1.1
  62. Host: reservedSSDPmulticastaddress
  63. NT: blenderassociation:blender
  64. NTS: ssdp:alive
  65. USN: someunique:idscheme3
  66. AL: <blender:ixl><http://foo/bar>
  67. Cache-Control: max-age = 7393
  68. To-do: HTTP headers are all ascii, the API may accept unicode, but convert to ascii before
  69. calling the rpc interface. The server keeps ascii version only.
  70. To-do: Support arbitrary content.
  71. */
  72. // Compose an SSDP alive message from the a SSDP Message structure, caller should
  73. // free the memory when done.
  74. BOOL ComposeSsdpResponse(const SSDP_REQUEST *Source, CHAR **pszBytes)
  75. {
  76. CHAR ResponseHeader[40] = "HTTP/1.1 200 OK";
  77. INT iLength = 0;
  78. INT iNumOfBytes = 0;
  79. CHAR * szBytes;
  80. INT i;
  81. iLength = strlen(ResponseHeader) + strlen(CRLF);
  82. if (Source->Headers[SSDP_NT] != NULL)
  83. {
  84. iLength += strlen(SsdpHeaderStr[SSDP_ST]) +
  85. strlen(COLON) +
  86. strlen(Source->Headers[SSDP_NT]) +
  87. strlen(CRLF);
  88. }
  89. if (Source->Headers[SSDP_LOCATION] != NULL)
  90. {
  91. iLength += strlen(SsdpHeaderStr[SSDP_LOCATION]) +
  92. strlen(COLON) +
  93. strlen(Source->Headers[SSDP_LOCATION]) +
  94. strlen(CRLF);
  95. }
  96. if (Source->Headers[SSDP_AL] != NULL)
  97. {
  98. iLength += strlen(SsdpHeaderStr[SSDP_AL]) +
  99. strlen(COLON) +
  100. strlen(Source->Headers[SSDP_AL]) +
  101. strlen(CRLF);
  102. }
  103. if (Source->Headers[SSDP_USN] != NULL)
  104. {
  105. iLength += strlen(SsdpHeaderStr[SSDP_USN]) +
  106. strlen(COLON) +
  107. strlen(Source->Headers[SSDP_USN]) +
  108. strlen(CRLF);
  109. }
  110. if (Source->Headers[SSDP_CACHECONTROL] != NULL)
  111. {
  112. iLength += strlen(SsdpHeaderStr[SSDP_CACHECONTROL]) +
  113. strlen(COLON) +
  114. strlen(Source->Headers[SSDP_CACHECONTROL]) +
  115. strlen(CRLF);
  116. }
  117. if (Source->Headers[GENA_SID] != NULL)
  118. {
  119. iLength += strlen(SsdpHeaderStr[GENA_SID]) +
  120. strlen(COLON) +
  121. strlen(Source->Headers[GENA_SID]) +
  122. strlen(CRLF);
  123. }
  124. if (Source->Headers[GENA_TIMEOUT] != NULL)
  125. {
  126. iLength += strlen(SsdpHeaderStr[GENA_TIMEOUT]) +
  127. strlen(COLON) +
  128. strlen(Source->Headers[GENA_TIMEOUT]) +
  129. strlen(CRLF);
  130. }
  131. if (Source->Headers[SSDP_SERVER] != NULL)
  132. {
  133. iLength += strlen(SsdpHeaderStr[SSDP_SERVER]) +
  134. strlen(COLON) +
  135. strlen(Source->Headers[SSDP_SERVER]) +
  136. strlen(CRLF);
  137. }
  138. if (Source->Headers[SSDP_EXT] != NULL)
  139. {
  140. iLength += strlen(SsdpHeaderStr[SSDP_EXT]) +
  141. strlen(COLON) +
  142. strlen(Source->Headers[SSDP_EXT]) +
  143. strlen(CRLF);
  144. }
  145. iLength += strlen(CRLF);
  146. szBytes = (CHAR *) midl_user_allocate(sizeof(CHAR) * iLength + 1);
  147. if (szBytes == NULL)
  148. {
  149. TraceTag(ttidSsdpParser, "Faled to allocate memory for the ssdp message.");
  150. return FALSE;
  151. }
  152. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s", ResponseHeader, CRLF);
  153. if (Source->Headers[SSDP_NT] != NULL)
  154. {
  155. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  156. SsdpHeaderStr[SSDP_ST], COLON,
  157. Source->Headers[SSDP_NT],CRLF);
  158. }
  159. if (Source->Headers[SSDP_USN] != NULL)
  160. {
  161. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  162. SsdpHeaderStr[SSDP_USN], COLON,
  163. Source->Headers[SSDP_USN],CRLF);
  164. }
  165. if (Source->Headers[SSDP_LOCATION] != NULL)
  166. {
  167. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  168. SsdpHeaderStr[SSDP_LOCATION], COLON,
  169. Source->Headers[SSDP_LOCATION],CRLF);
  170. }
  171. if (Source->Headers[SSDP_AL] != NULL)
  172. {
  173. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  174. SsdpHeaderStr[SSDP_AL], COLON,
  175. Source->Headers[SSDP_AL],CRLF);
  176. }
  177. if (Source->Headers[SSDP_CACHECONTROL] != NULL)
  178. {
  179. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  180. SsdpHeaderStr[SSDP_CACHECONTROL], COLON,
  181. Source->Headers[SSDP_CACHECONTROL],CRLF);
  182. }
  183. if (Source->Headers[GENA_SID] != NULL)
  184. {
  185. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  186. SsdpHeaderStr[GENA_SID], COLON,
  187. Source->Headers[GENA_SID],CRLF);
  188. }
  189. if (Source->Headers[GENA_TIMEOUT] != NULL)
  190. {
  191. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  192. SsdpHeaderStr[GENA_TIMEOUT], COLON,
  193. Source->Headers[GENA_TIMEOUT],CRLF);
  194. }
  195. if (Source->Headers[SSDP_SERVER] != NULL)
  196. {
  197. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  198. SsdpHeaderStr[SSDP_SERVER], COLON,
  199. Source->Headers[SSDP_SERVER],CRLF);
  200. }
  201. if (Source->Headers[SSDP_EXT] != NULL)
  202. {
  203. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  204. SsdpHeaderStr[SSDP_EXT], COLON,
  205. Source->Headers[SSDP_EXT],CRLF);
  206. }
  207. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s",CRLF);
  208. *pszBytes = szBytes;
  209. return TRUE;
  210. }
  211. // To-do: optimize, cache does not care about the request/response line
  212. BOOL ComposeSsdpRequest(const SSDP_REQUEST *Source, CHAR **pszBytes)
  213. {
  214. INT iLength = 0;
  215. INT iNumOfBytes = 0;
  216. CHAR iLifeTime[10];
  217. CHAR * szBytes;
  218. INT i;
  219. if (Source->Method != SSDP_INVALID && Source->RequestUri != NULL)
  220. {
  221. iLength += strlen(SsdpMethodStr[Source->Method]) + strlen(SP) +
  222. strlen(Source->RequestUri) + strlen(SP) +
  223. strlen(HTTP_VERSION) + strlen(CRLF);
  224. }
  225. for (i = 0; i < NUM_OF_HEADERS; i++)
  226. {
  227. if (Source->Headers[i] != NULL)
  228. {
  229. iLength += strlen(SsdpHeaderStr[i]) + strlen(COLON) +
  230. strlen(Source->Headers[i]) + strlen(CRLF);
  231. }
  232. }
  233. iLength += strlen(CRLF);
  234. szBytes = (CHAR *) malloc(sizeof(CHAR) * iLength + 1);
  235. if (szBytes == NULL)
  236. {
  237. TraceTag(ttidSsdpParser, "Faled to allocate memory for the ssdp message.");
  238. return FALSE;
  239. }
  240. if (Source->Method != SSDP_INVALID && Source->RequestUri != NULL)
  241. {
  242. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s%s%s",
  243. SsdpMethodStr[Source->Method], SP,
  244. Source->RequestUri, SP, HTTP_VERSION, CRLF);
  245. }
  246. for (i = 0; i < NUM_OF_HEADERS; i++)
  247. {
  248. if (Source->Headers[i] != NULL)
  249. {
  250. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s",
  251. SsdpHeaderStr[i], COLON,
  252. Source->Headers[i],CRLF);
  253. }
  254. }
  255. iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s",CRLF);
  256. *pszBytes = szBytes;
  257. return TRUE;
  258. }
  259. BOOL FReplaceTokenInLocation(LPCSTR szIn, LPSTR szReplace, LPSTR *pszOut)
  260. {
  261. CHAR * pch;
  262. Assert(pszOut);
  263. *pszOut = NULL;
  264. if (pch = strstr(szIn, c_szReplaceGuid))
  265. {
  266. LPSTR szOut;
  267. DWORD cbOut;
  268. cbOut = (lstrlen(szIn) - c_cchReplaceGuid + lstrlen(szReplace) + 1) *
  269. sizeof(CHAR);
  270. szOut = (LPSTR)malloc(cbOut);
  271. if (szOut)
  272. {
  273. lstrcpyn(szOut, szIn, (int)(pch - szIn + 1));
  274. lstrcat(szOut, szReplace);
  275. pch += c_cchReplaceGuid;
  276. lstrcat(szOut, pch);
  277. *pszOut = szOut;
  278. }
  279. else
  280. {
  281. return FALSE;
  282. }
  283. }
  284. return TRUE;
  285. }
  286. // Pre-Conditions:
  287. // Result->Headers[CONTENT_LENGTH] contains only digits.
  288. // pContent points to the first char "\r\n\r\n".
  289. // Return szValue:
  290. // returns FALSE if there not enough content.
  291. BOOL ParseContent(const char *pContent, DWORD cbContent, SSDP_REQUEST *Result)
  292. {
  293. if(!Result->Headers[CONTENT_LENGTH])
  294. {
  295. return TRUE;
  296. }
  297. DWORD dwContentLength = strtoul(Result->Headers[CONTENT_LENGTH], NULL, 10);
  298. if (dwContentLength == 0)
  299. {
  300. // If it can't be conver to a number or it is 0.
  301. TraceTag(ttidSsdpParser, "Content-Length is 0.");
  302. return TRUE;
  303. }
  304. else if ((cbContent == (DWORD)(-1)) || (cbContent == dwContentLength))
  305. {
  306. Result->Content = (CHAR*) midl_user_allocate(dwContentLength + 1);
  307. if (Result->Content == NULL)
  308. {
  309. TraceTag(ttidSsdpParser, "Failed to allocate memory for Content");
  310. return FALSE;
  311. }
  312. else
  313. {
  314. lstrcpyn(Result->Content,pContent, dwContentLength + 1);
  315. return TRUE;
  316. }
  317. }
  318. return FALSE;
  319. }
  320. CHAR * ParseRequestLine(CHAR * szMessage, SSDP_REQUEST *Result)
  321. {
  322. CHAR *token;
  323. INT i;
  324. Assert(NULL != szMessage);
  325. // Make sure we don't go past the end of the buffer
  326. CHAR * pchEnd = szMessage + lstrlen(szMessage);
  327. // Get the HTTP method
  328. token = strtok(szMessage," \t\n");
  329. if (token == NULL)
  330. {
  331. TraceTag(ttidSsdpParser, "Parser could not locate the seperator, "
  332. "space, tab or eol");
  333. return NULL;
  334. }
  335. for (i = 0; i < NUM_OF_METHODS; i++)
  336. {
  337. if (_stricmp(SsdpMethodStr[i],token) == 0)
  338. {
  339. Result->Method = (SSDP_METHOD)i;
  340. break;
  341. }
  342. }
  343. if (i == NUM_OF_METHODS)
  344. {
  345. TraceTag(ttidSsdpParser, "Parser could not find method . "
  346. "Received %s", token);
  347. return NULL;
  348. }
  349. // Get the Request-URI
  350. token = strtok(NULL," ");
  351. if (token == NULL)
  352. {
  353. TraceTag(ttidSsdpParser, "Parser could not find the url in the "
  354. "message.");
  355. return NULL;
  356. }
  357. // Ingore the name space parsing for now, get the string after the last '/'.
  358. Result->RequestUri = (CHAR*) midl_user_allocate(strlen(token) + 1);
  359. if (Result->RequestUri == NULL)
  360. {
  361. TraceTag(ttidSsdpParser, "Parser could not allocate memory for url.");
  362. return NULL;
  363. }
  364. // Record the service.
  365. strcpy(Result->RequestUri, token);
  366. // Get the version number
  367. token = strtok(NULL," \t\r");
  368. // To-Do: Record the version number when necessary.
  369. if (token == NULL)
  370. {
  371. TraceTag(ttidSsdpParser, "Failed to get the version in the request "
  372. "header.");
  373. FreeSsdpRequest(Result);
  374. return NULL;
  375. }
  376. if (_stricmp(token, "HTTP/1.1") != 0)
  377. {
  378. TraceTag(ttidSsdpParser, "The version specified in the request "
  379. "message is not HTTP/1.1");
  380. FreeSsdpRequest(Result);
  381. return NULL;
  382. }
  383. // point to the rest of the header data, after the current token
  384. token += lstrlen(token) + 1;
  385. if (token >= pchEnd)
  386. {
  387. TraceTag(ttidSsdpParser, "no data following HTTP/1.1 in the request");
  388. FreeSsdpRequest(Result);
  389. return NULL;
  390. }
  391. return token;
  392. }
  393. BOOL VerifySsdpHeaders(SSDP_REQUEST *Result)
  394. {
  395. if (Result->Method == SSDP_M_SEARCH)
  396. {
  397. if (Result->Headers[SSDP_ST] == NULL ||
  398. Result->Headers[SSDP_MX] == NULL ||
  399. *Result->Headers[SSDP_MX] == L'\0' ||
  400. *Result->Headers[SSDP_ST] == L'\0')
  401. {
  402. TraceTag(ttidSsdpParser, "ST and MX header should not be NULL for M-SEARCH");
  403. return FALSE;
  404. }
  405. if (Result->Headers[SSDP_MAN] == NULL || lstrcmpi(Result->Headers[SSDP_MAN], "\"ssdp:discover\""))
  406. {
  407. TraceTag(ttidSsdpParser, "MAN header for M-SEARCH must be \"ssdp:discover\"");
  408. return FALSE;
  409. }
  410. if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT))
  411. {
  412. TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900"
  413. "for n M-SEARCH message.");
  414. return FALSE;
  415. }
  416. }
  417. if (Result->Headers[SSDP_MX] != NULL &&
  418. IsStrDigits(Result->Headers[SSDP_MX]) == FALSE)
  419. {
  420. TraceTag(ttidSsdpParser, "MX header should be all digits");
  421. return FALSE;
  422. }
  423. if (Result->Method == SSDP_NOTIFY)
  424. {
  425. if (Result->Headers[SSDP_NT] == NULL ||
  426. Result->Headers[SSDP_NTS] == NULL)
  427. {
  428. TraceTag(ttidSsdpParser, "NT and NTS headers should not be NULL for a NOTIFY message.");
  429. return FALSE;
  430. }
  431. // Assume NOTIFY other than upnp:propchange requires USN header.
  432. // Currently, ssdp:alive and ssdp:byebye
  433. if (lstrcmpi(Result->Headers[SSDP_NTS], "upnp:propchange"))
  434. {
  435. if (Result->Headers[SSDP_USN] == NULL)
  436. {
  437. TraceTag(ttidSsdpParser, "USN headers should not be NULL for "
  438. "a NOTIFY message.");
  439. return FALSE;
  440. }
  441. if (!lstrcmpi(Result->Headers[SSDP_NTS], "ssdp:alive"))
  442. {
  443. // ssdp:alive messages must have a location header
  444. if (Result->Headers[SSDP_LOCATION] == NULL)
  445. {
  446. TraceTag(ttidSsdpParser, "LOCATION header can not be NULL "
  447. "for a NOTIFY message.");
  448. return FALSE;
  449. }
  450. // ssdp:alive messages must have a SERVER header
  451. if (Result->Headers[SSDP_SERVER] == NULL)
  452. {
  453. TraceTag(ttidSsdpParser, "SERVER header can not be NULL "
  454. "for a NOTIFY message.");
  455. return FALSE;
  456. }
  457. if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT))
  458. {
  459. TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900"
  460. "for a NOTIFY message.");
  461. return FALSE;
  462. }
  463. }
  464. else if (!lstrcmpi(Result->Headers[SSDP_NTS], "ssdp:byebye"))
  465. {
  466. if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT))
  467. {
  468. TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900"
  469. "for a NOTIFY message.");
  470. return FALSE;
  471. }
  472. }
  473. }
  474. }
  475. if (Result->Headers[CONTENT_LENGTH] != NULL &&
  476. IsStrDigits(Result->Headers[CONTENT_LENGTH]) == FALSE )
  477. {
  478. TraceTag(ttidSsdpParser, "Content length header should be all digits");
  479. return FALSE;
  480. }
  481. return TRUE;
  482. }
  483. BOOL HasContentBody(PSSDP_REQUEST Result)
  484. {
  485. return (Result->Headers[CONTENT_LENGTH] != NULL);
  486. }
  487. BOOL ParseSsdpRequest(CHAR * szMessage, PSSDP_REQUEST Result)
  488. {
  489. CHAR *szHeaders;
  490. szHeaders = ParseRequestLine(szMessage, Result);
  491. if (szHeaders == NULL)
  492. {
  493. return FALSE;
  494. }
  495. char *pContent = ParseHeaders(szHeaders, Result);
  496. if ( pContent == NULL)
  497. {
  498. return FALSE;
  499. }
  500. else
  501. {
  502. if (VerifySsdpHeaders(Result) == FALSE)
  503. {
  504. return FALSE;
  505. }
  506. // Headers are OK.
  507. if (Result->Headers[CONTENT_LENGTH] != NULL)
  508. {
  509. // To-Do: Maybe we can share the this routine with those
  510. // in ProcessTcpReceiveData();
  511. // In that case, we need catch the return szValue of ParseContent
  512. // and probably return a more meaningful error code.
  513. ParseContent(pContent, (DWORD)(-1), Result);
  514. }
  515. return TRUE;
  516. }
  517. }
  518. // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
  519. // Returns a pointer to the first CHAR after the status line
  520. // Returns NULL if fail to parse status line
  521. BOOL ParseSsdpResponse(CHAR *szMessage, SSDP_REQUEST *Result)
  522. {
  523. CHAR *token;
  524. CHAR *szHeaders;
  525. Assert(NULL != szMessage);
  526. // Make sure we don't go past the end of the buffer
  527. CHAR * pchEnd = szMessage + lstrlen(szMessage);
  528. // get the version
  529. token = strtok(szMessage," \t\n");
  530. if (token == NULL)
  531. {
  532. TraceTag(ttidSsdpParser, "Response: Parser could not locate the "
  533. "seperator, space, tab or eol");
  534. return FALSE;
  535. }
  536. if (_stricmp(token, "HTTP/1.1") != 0)
  537. {
  538. TraceTag(ttidSsdpParser, "The version specified in the response "
  539. "message is not HTTP/1.1");
  540. return FALSE;
  541. }
  542. // get the response code
  543. token = strtok(NULL," ");
  544. if (token == NULL)
  545. {
  546. TraceTag(ttidSsdpParser, "Parser could not find the url in the "
  547. "message.");
  548. return FALSE;
  549. }
  550. if (_stricmp(token, "200") != 0)
  551. {
  552. TraceTag(ttidSsdpParser, "The response code in the response message "
  553. "is not HTTP/1.1");
  554. return FALSE;
  555. }
  556. // get the response message, no need for now.
  557. token = strtok(NULL," \t\r");
  558. if (token == NULL)
  559. {
  560. TraceTag(ttidSsdpParser, "Failed to get the version in the request "
  561. "header.");
  562. return FALSE;
  563. }
  564. szHeaders = token + strlen(token) + 1;
  565. if (szHeaders >= pchEnd)
  566. {
  567. TraceTag(ttidSsdpParser, "no data following HTTP/1.1 200 in the request");
  568. return FALSE;
  569. }
  570. char *pContent = ParseHeaders(szHeaders, Result);
  571. if (pContent == NULL || Result->Headers[SSDP_USN] == NULL)
  572. {
  573. return FALSE;
  574. } else
  575. {
  576. if (Result->Headers[CONTENT_LENGTH] != NULL)
  577. {
  578. ParseContent(pContent, (DWORD)(-1), Result);
  579. }
  580. return TRUE;
  581. }
  582. }
  583. BOOL ParseCacheControlHeader(SSDP_REQUEST *Result)
  584. {
  585. if (Result->Headers[SSDP_CACHECONTROL])
  586. {
  587. // Further parse the cache-control header
  588. //
  589. CHAR * szValue = strstr(Result->Headers[SSDP_CACHECONTROL], c_szMaxAge);
  590. if (szValue)
  591. {
  592. CHAR * szTemp = szValue + c_cchMaxAge;
  593. strtrim(&szTemp);
  594. if (*szTemp != '=')
  595. {
  596. TraceTag(ttidSsdpParser, "Invalid max-age directive"
  597. " in cache-control header.");
  598. return FALSE;
  599. }
  600. else
  601. {
  602. szTemp++;
  603. memcpy(Result->Headers[SSDP_CACHECONTROL], c_szMaxAge, c_cchMaxAge);
  604. Result->Headers[SSDP_CACHECONTROL][c_cchMaxAge] = '=';
  605. strtrim(&szTemp);
  606. szValue = szTemp;
  607. while (isdigit(*szTemp))
  608. {
  609. szTemp++;
  610. }
  611. if (szTemp == szValue)
  612. {
  613. // no digits found
  614. TraceTag(ttidSsdpParser, "Invalid max-age directive"
  615. " in cache-control header.");
  616. return FALSE;
  617. }
  618. memcpy(Result->Headers[SSDP_CACHECONTROL] + c_cchMaxAge+1,
  619. szValue, (size_t)(szTemp - szValue));
  620. // Nul term the string so the cache-control
  621. // header should now be "max-age=398733" and
  622. // nothing more or less
  623. size_t cch = c_cchMaxAge + 1 + (szTemp - szValue);
  624. Result->Headers[SSDP_CACHECONTROL][cch] = 0;
  625. }
  626. }
  627. else
  628. {
  629. TraceTag(ttidSsdpParser, "Cache-control header"
  630. "did not include max-age directive.");
  631. return TRUE;
  632. }
  633. }
  634. return TRUE;
  635. }
  636. char * ParseHeaders(CHAR *szMessage, SSDP_REQUEST *Result)
  637. {
  638. CHAR *token;
  639. INT i = NUM_OF_HEADERS;
  640. INT iPrevHeader = NUM_OF_HEADERS;
  641. Assert(NULL != szMessage);
  642. if (NULL == strstr(szMessage, szHeaderEnd))
  643. {
  644. TraceTag(ttidSsdpParser, "Invalid header - does not end with double CRLF");
  645. return NULL;
  646. }
  647. // Get the next header
  648. token = strtok(szMessage, "\r\n");
  649. while (token != NULL)
  650. {
  651. CHAR * pHeaderSep; // points to the ':' that seperates the header and its content.
  652. CHAR * pHeaderCopy;
  653. CHAR * pBeyondTokenEnd;
  654. pBeyondTokenEnd = token + strlen(token) + 1;
  655. if ((*token == ' ' || *token == '\t') && iPrevHeader != NUM_OF_HEADERS)
  656. {
  657. // this is a continuation of the last line
  658. strtrim(&token);
  659. if (Result->Headers[iPrevHeader])
  660. {
  661. // we already have this header, so add this data to it.
  662. CHAR* szTemp = (CHAR*)midl_user_allocate(
  663. sizeof(CHAR) * (strlen(token) + strlen(Result->Headers[iPrevHeader]) + 3));
  664. if (szTemp)
  665. {
  666. strcpy(szTemp, Result->Headers[iPrevHeader]);
  667. strcat(szTemp, " ");
  668. strcat(szTemp, token);
  669. midl_user_free(Result->Headers[iPrevHeader]);
  670. Result->Headers[iPrevHeader] = szTemp;
  671. }
  672. else
  673. {
  674. TraceTag(ttidSsdpParser, "Failed to allocate memory "
  675. "for token %s", token);
  676. FreeSsdpRequest(Result);
  677. return NULL;
  678. }
  679. }
  680. else
  681. {
  682. TraceTag(ttidSsdpParser, "Memory not already allocated for header %s",
  683. SsdpHeaderStr[iPrevHeader]);
  684. FreeSsdpRequest(Result);
  685. return NULL;
  686. }
  687. }
  688. else
  689. {
  690. pHeaderSep = strchr( token, ':' );
  691. if (pHeaderSep == NULL)
  692. {
  693. TraceTag(ttidSsdpParser, "Token %s does not have a ':', ignored.",
  694. token);
  695. }
  696. else
  697. {
  698. *pHeaderSep = '\0';
  699. strtrim(&token);
  700. // determine which header we are looking at
  701. for (i = 0; i < NUM_OF_HEADERS; i++)
  702. {
  703. if (_stricmp(SsdpHeaderStr[i],token) == 0)
  704. break;
  705. }
  706. if (i < NUM_OF_HEADERS)
  707. {
  708. CHAR *szValue;
  709. szValue = pHeaderSep + 1;
  710. strtrim(&szValue);
  711. if (Result->Headers[i])
  712. {
  713. // we already have this header, so add this data to it.
  714. CHAR* szTemp = (CHAR*)midl_user_allocate(
  715. sizeof(CHAR) * (strlen(szValue) + strlen(Result->Headers[i]) + 3));
  716. if (szTemp)
  717. {
  718. strcpy(szTemp, Result->Headers[i]);
  719. strcat(szTemp, ", ");
  720. strcat(szTemp, szValue);
  721. midl_user_free(Result->Headers[i]);
  722. Result->Headers[i] = szTemp;
  723. }
  724. else
  725. {
  726. midl_user_free(Result->Headers[i]);
  727. Result->Headers[i] = NULL;
  728. }
  729. }
  730. else
  731. {
  732. Result->Headers[i] = (CHAR *) midl_user_allocate(
  733. sizeof(CHAR) * (strlen(szValue) + 1));
  734. if (Result->Headers[i])
  735. {
  736. strcpy(Result->Headers[i], szValue);
  737. }
  738. }
  739. if (Result->Headers[i] == NULL)
  740. {
  741. TraceTag(ttidSsdpParser, "Failed to allocate memory "
  742. "for szValue %s",szValue);
  743. FreeSsdpRequest(Result);
  744. return NULL;
  745. }
  746. }
  747. else
  748. {
  749. // Ignore not recognized header
  750. TraceTag(ttidSsdpParser, "Token %s does not match any SSDP "
  751. "headers",token);
  752. }
  753. }
  754. }
  755. // Get the next header
  756. if (!strncmp(pBeyondTokenEnd, szEndOfHeaders, END_HEADERS_SIZE))
  757. {
  758. // no more headers. parse what we have
  759. if (!ParseCacheControlHeader(Result))
  760. {
  761. FreeSsdpRequest(Result);
  762. return NULL;
  763. }
  764. return (pBeyondTokenEnd + END_HEADERS_SIZE);
  765. }
  766. else
  767. {
  768. token = strtok(NULL, "\r\n");
  769. iPrevHeader = i;
  770. }
  771. }
  772. // We should always have a "\r\n\r\n" in any legal message.
  773. TraceTag(ttidSsdpParser, "Received message does not contain \\r\\n\\r\\n. Ignored. ");
  774. FreeSsdpRequest(Result);
  775. return NULL;
  776. }
  777. BOOL InitializeSsdpRequest(SSDP_REQUEST *pRequest)
  778. {
  779. INT i;
  780. pRequest->Method = SSDP_INVALID;
  781. pRequest->RequestUri = NULL;
  782. for (i = 0; i < NUM_OF_HEADERS; i++)
  783. {
  784. pRequest->Headers[i] = NULL;
  785. }
  786. pRequest->ContentType = NULL;
  787. pRequest->Content = NULL;
  788. return TRUE;
  789. }
  790. VOID FreeSsdpRequest(SSDP_REQUEST *pSsdpRequest)
  791. {
  792. INT i = 0;
  793. if (pSsdpRequest->Content != NULL)
  794. {
  795. midl_user_free(pSsdpRequest->Content);
  796. pSsdpRequest->Content = NULL;
  797. }
  798. if (pSsdpRequest->ContentType != NULL)
  799. {
  800. midl_user_free(pSsdpRequest->ContentType);
  801. pSsdpRequest->ContentType = NULL;
  802. }
  803. if (pSsdpRequest->RequestUri != NULL)
  804. {
  805. midl_user_free(pSsdpRequest->RequestUri);
  806. pSsdpRequest->RequestUri = NULL;
  807. }
  808. for (i = 0; i < NUM_OF_HEADERS; i++)
  809. {
  810. if (pSsdpRequest->Headers[i] != NULL)
  811. {
  812. midl_user_free(pSsdpRequest->Headers[i]);
  813. pSsdpRequest->Headers[i] = NULL;
  814. }
  815. }
  816. }
  817. // Get rid of leading or trailing white space or tab.
  818. VOID PrintSsdpRequest(const SSDP_REQUEST *pssdpRequest)
  819. {
  820. INT i;
  821. for (i = 0; i < NUM_OF_HEADERS; i++)
  822. {
  823. if (pssdpRequest->Headers[i] == NULL)
  824. {
  825. TraceTag(ttidSsdpParser, "%s = (NULL) ",SsdpHeaderStr[i],
  826. pssdpRequest->Headers[i]);
  827. }
  828. else
  829. {
  830. TraceTag(ttidSsdpParser, "%s = (%s) ",SsdpHeaderStr[i],
  831. pssdpRequest->Headers[i]);
  832. }
  833. }
  834. }
  835. // Assume szValue does not have beginning or trailing spaces.
  836. INT GetMaxAgeFromCacheControl(const CHAR *szValue)
  837. {
  838. CHAR * pEqual;
  839. _int64 Temp;
  840. if (szValue == NULL)
  841. {
  842. return -1;
  843. }
  844. pEqual = strchr(szValue, '=');
  845. if (pEqual == NULL)
  846. {
  847. return -1;
  848. }
  849. Temp = _atoi64(pEqual+1);
  850. if (Temp > UINT_MAX / 1000)
  851. {
  852. TraceTag(ttidSsdpAnnounce, "Life time exceeded the UINT limit. "
  853. "Set to limit");
  854. Temp = UINT_MAX;
  855. }
  856. return (UINT)Temp;
  857. }
  858. BOOL ConvertToByebyeNotify(PSSDP_REQUEST pSsdpRequest)
  859. {
  860. CHAR * szTemp = "ssdp:byebye";
  861. free(pSsdpRequest->Headers[SSDP_NTS]);
  862. pSsdpRequest->Headers[SSDP_NTS] = NULL;
  863. pSsdpRequest->Headers[SSDP_NTS] = SzaDupSza(szTemp);
  864. if (pSsdpRequest->Headers[SSDP_NTS] == NULL)
  865. {
  866. return FALSE;
  867. }
  868. else
  869. {
  870. return TRUE;
  871. }
  872. }
  873. BOOL ConvertToAliveNotify(PSSDP_REQUEST pSsdpRequest)
  874. {
  875. CHAR * szTemp = "ssdp:alive";
  876. Assert(pSsdpRequest->Headers[SSDP_ST] != NULL);
  877. Assert(pSsdpRequest->Headers[SSDP_NTS] == NULL);
  878. pSsdpRequest->Headers[SSDP_NTS] = SzaDupSza(szTemp);
  879. if (pSsdpRequest->Headers[SSDP_NTS] == NULL)
  880. {
  881. return FALSE;
  882. }
  883. else
  884. {
  885. pSsdpRequest->Headers[SSDP_NT] = pSsdpRequest->Headers[SSDP_ST];
  886. pSsdpRequest->Headers[SSDP_ST] = NULL;
  887. return TRUE;
  888. }
  889. }
  890. BOOL CompareSsdpRequest(const SSDP_REQUEST * pRequestA, const SSDP_REQUEST * pRequestB)
  891. {
  892. INT i;
  893. for (i = 0; i < NUM_OF_HEADERS; i++)
  894. {
  895. if ((pRequestA->Headers[i] == NULL &&
  896. pRequestB->Headers[i]!= NULL) ||
  897. (pRequestA->Headers[i] != NULL &&
  898. pRequestB->Headers[i]== NULL))
  899. {
  900. return FALSE;
  901. }
  902. else if (pRequestA->Headers[i] != NULL &&
  903. pRequestB->Headers[i] != NULL)
  904. {
  905. if (strcmp(pRequestA->Headers[i], pRequestB->Headers[i]) != 0)
  906. {
  907. TraceTag(ttidSsdpParser, "Different headers index %d",i);
  908. return FALSE;
  909. }
  910. }
  911. }
  912. Assert(pRequestA->Content == NULL && pRequestB->Content == NULL);
  913. Assert(pRequestA->ContentType == NULL && pRequestB->ContentType == NULL);
  914. // We ignore Request URI, as they should always be * for alive and byebye.
  915. return TRUE;
  916. }
  917. // Deep copy
  918. BOOL CopySsdpRequest(PSSDP_REQUEST Destination, const SSDP_REQUEST * Source)
  919. {
  920. INT i;
  921. ZeroMemory(Destination, sizeof(*Destination));
  922. Destination->Method = Source->Method ;
  923. for (i = 0; i < NUM_OF_HEADERS; i++)
  924. {
  925. if (Source->Headers[i] != NULL)
  926. {
  927. Destination->Headers[i] = (CHAR *) midl_user_allocate(
  928. strlen(Source->Headers[i]) + 1);
  929. if (Destination->Headers[i] == NULL)
  930. {
  931. goto cleanup;
  932. }
  933. else
  934. {
  935. strcpy(Destination->Headers[i], Source->Headers[i]);
  936. }
  937. }
  938. }
  939. if (Source->Content != NULL)
  940. {
  941. Destination->Content = (CHAR *) midl_user_allocate(
  942. strlen(Source->Content) + 1);
  943. if (Destination->Content == NULL)
  944. {
  945. goto cleanup;
  946. }
  947. else
  948. {
  949. strcpy(Destination->Content, Source->Content);
  950. }
  951. }
  952. if (Source->ContentType != NULL)
  953. {
  954. Destination->ContentType = (CHAR *) midl_user_allocate(
  955. strlen(Source->ContentType) + 1);
  956. if (Destination->ContentType == NULL)
  957. {
  958. goto cleanup;
  959. }
  960. else
  961. {
  962. strcpy(Destination->ContentType, Source->ContentType);
  963. }
  964. }
  965. if (Source->RequestUri != NULL)
  966. {
  967. Destination->RequestUri = (CHAR *) midl_user_allocate(
  968. strlen(Source->RequestUri) + 1);
  969. if (Destination->RequestUri == NULL)
  970. {
  971. goto cleanup;
  972. }
  973. else
  974. {
  975. strcpy(Destination->RequestUri, Source->RequestUri);
  976. }
  977. }
  978. Destination->guidInterface = Source->guidInterface;
  979. return TRUE;
  980. cleanup:
  981. FreeSsdpRequest(Destination);
  982. return FALSE;
  983. }
  984. BOOL IsStrDigits(LPSTR pszStr)
  985. {
  986. int i = 0;
  987. while (pszStr[i] != '\0')
  988. {
  989. if (isdigit(pszStr[i++]) == 0)
  990. {
  991. return FALSE;
  992. }
  993. }
  994. return TRUE;
  995. }
  996. VOID strtrim(CHAR ** pszStr)
  997. {
  998. CHAR *end;
  999. CHAR *begin;
  1000. // Empty string. Nothing to do.
  1001. //
  1002. if (!(**pszStr))
  1003. {
  1004. return;
  1005. }
  1006. begin = *pszStr;
  1007. end = begin + strlen(*pszStr) - 1;
  1008. while (*begin == ' ' || *begin == '\t')
  1009. {
  1010. begin++;
  1011. }
  1012. *pszStr = begin;
  1013. while ((end > begin) && (*end == ' ' || *end == '\t'))
  1014. {
  1015. end--;
  1016. }
  1017. *(end+1) = '\0';
  1018. }
  1019. CHAR* IsHeadersComplete(const CHAR *szHeaders)
  1020. {
  1021. return strstr(szHeaders, szHeaderEnd);
  1022. }