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.

343 lines
9.8 KiB

  1. /*--
  2. Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
  3. Module Name: ISAPI.CPP
  4. Abstract: ISAPI handling code
  5. --*/
  6. #include "pch.h"
  7. #pragma hdrstop
  8. #include "httpd.h"
  9. // Prefix for GetServerVariable for generic HTTP header retrieval, so "HTTPD_FOOBAR" gets HTTP header FOOBAR.
  10. static const char cszHTTP[] = "HTTP_";
  11. static const DWORD dwHTTP = CONSTSIZEOF(cszHTTP);
  12. // This function is used when looking through HTTP headers for HTTP_VARIABLE. We
  13. // can't use strcmp because headers (for most part) have words separated by "-",
  14. // the pszVar format has vars separated by "_". IE pszVar=HTTP_ACCEPT_LANGUAGE
  15. // should return for us HTTP header "ACCEPT-LANGUAGE"
  16. BOOL GetVariableStrCmp(PSTR pszHeader, PSTR pszVar, DWORD_PTR dwLen)
  17. {
  18. BOOL fRet = FALSE;
  19. for (DWORD i = 0; i < dwLen; i++)
  20. {
  21. if ( (tolower(*pszHeader) != tolower(*pszVar)) &&
  22. (*pszVar != '_' && *pszHeader != '-'))
  23. {
  24. goto done;
  25. }
  26. pszHeader++;
  27. pszVar++;
  28. }
  29. fRet = (*pszHeader == ':');
  30. done:
  31. return fRet;
  32. }
  33. BOOL CHttpRequest::GetServerVariable(PSTR pszVar, PVOID pvOutBuf, PDWORD pdwOutSize, BOOL fFromFilter)
  34. {
  35. DWORD dwLen;
  36. char szBuf[MAXHEADERS];
  37. PSTR pszRet = (PSTR)-1;
  38. PSTR pszTrav = NULL;
  39. CHAR chSave;
  40. if (0==_stricmp(pszVar, "APPL_MD_PATH"))
  41. pszRet = "/LM/W3SVC/1/ROOT/";
  42. else if (0==_stricmp(pszVar, "APPL_PHYSICAL_PATH"))
  43. {
  44. strcpy (szBuf, "/");
  45. dwLen = sizeof(szBuf);
  46. if (MapURLToPath (szBuf, &dwLen))
  47. pszRet = szBuf;
  48. }
  49. else if (0==_stricmp(pszVar, "SERVER_PORT"))
  50. {
  51. _itoa (g_pVars->m_dwListenPort, szBuf, 10);
  52. pszRet = szBuf;
  53. }
  54. else if (0==_stricmp(pszVar, "AUTH_TYPE"))
  55. pszRet = m_pszAuthType;
  56. else if (0 == _stricmp(pszVar, "AUTH_USER"))
  57. pszRet = m_pszRemoteUser;
  58. else if (0 == _stricmp(pszVar, "AUTH_PASSWORD"))
  59. pszRet = m_pszPassword;
  60. else if (0==_stricmp(pszVar, "CONTENT_LENGTH"))
  61. {
  62. sprintf(szBuf, "%d", m_dwContentLength);
  63. pszRet = szBuf;
  64. }
  65. else if (0==_stricmp(pszVar, "CONTENT_TYPE"))
  66. pszRet = m_pszContentType;
  67. else if (0==_stricmp(pszVar, "PATH_INFO"))
  68. pszRet = m_pszPathInfo;
  69. else if (0==_stricmp(pszVar, "PATH_TRANSLATED"))
  70. pszRet = m_pszPathTranslated;
  71. else if (0==_stricmp(pszVar, "QUERY_STRING"))
  72. pszRet = m_pszQueryString;
  73. else if (0==_stricmp(pszVar, "REMOTE_ADDR") || 0==_stricmp(pszVar, "REMOTE_HOST"))
  74. {
  75. GetRemoteAddress(m_socket, szBuf);
  76. pszRet = szBuf;
  77. }
  78. // Note: The following is a non-standard ISAPI variable
  79. //
  80. else if (0==_stricmp(pszVar, "LOCAL_ADDR"))
  81. {
  82. GetLocalAddress(m_socket, szBuf);
  83. pszRet = szBuf;
  84. }
  85. // ----End note
  86. else if (0==_stricmp(pszVar, "REMOTE_USER"))
  87. pszRet = m_pszRemoteUser;
  88. else if (0==_stricmp(pszVar, "UNMAPPED_REMOTE_USER"))
  89. pszRet = m_pszRemoteUser; /*m_pszRawRemoteUser; BUBUG: what is rawremoteuser?*/
  90. else if (0==_stricmp(pszVar, "REQUEST_METHOD"))
  91. pszRet = m_pszMethod;
  92. else if (0==_stricmp(pszVar, "URL"))
  93. {
  94. pszRet = m_pszURL;
  95. }
  96. else if (0==_stricmp(pszVar, "SCRIPT_NAME"))
  97. {
  98. if (fFromFilter)
  99. pszRet = NULL;
  100. else
  101. pszRet = m_pszURL;
  102. }
  103. else if (0==_stricmp(pszVar, "SERVER_NAME"))
  104. {
  105. if (0 != gethostname(szBuf, sizeof(szBuf)))
  106. szBuf[0] = '\0';
  107. pszRet = szBuf;
  108. }
  109. // HTTP_VERSION is version info as received from the client
  110. else if (0==_stricmp(pszVar, "HTTP_VERSION"))
  111. {
  112. sprintf(szBuf, cszHTTPVER, HIWORD(m_dwVersion), LOWORD(m_dwVersion));
  113. pszRet = szBuf;
  114. }
  115. // SERVER_PROTOCOL is the version of http server supports, currently 1.0
  116. else if (0==_stricmp(pszVar, "SERVER_PROTOCOL"))
  117. {
  118. strcpy(szBuf,"HTTP/1.1");
  119. pszRet = szBuf;
  120. }
  121. else if (0==_stricmp(pszVar, "SERVER_SOFTWARE"))
  122. pszRet = (PSTR)g_pVars->m_pszServerID;
  123. else if (0==_stricmp(pszVar, "ALL_HTTP"))
  124. pszRet = 0;
  125. // ALL_RAW return http headers, other than the simple request line. (fixes BUG 11991)
  126. // The way our buffer is set up, we can have POST data immediatly following
  127. // header data. So the client doesn't get confused, we have to set a \0 to it.
  128. else if (0 == _stricmp(pszVar, "ALL_RAW"))
  129. {
  130. pszRet = m_bufRequest.Headers();
  131. // skip past simple request line.
  132. pszRet = strstr(pszRet,"\r\n");
  133. pszRet += 2;
  134. // If there's unaccessed data, buffer has POST data in it
  135. if (m_bufRequest.HasPostData())
  136. {
  137. pszTrav = strstr(pszRet,("\r\n\r\n")) + 4;
  138. chSave = *pszTrav; *pszTrav = 0;
  139. }
  140. }
  141. else if (0==_stricmp(pszVar, "HTTP_ACCEPT"))
  142. pszRet = m_pszAccept;
  143. else if (0==_strnicmp(pszVar,cszHTTP,dwHTTP))
  144. {
  145. PSTR pszStart = pszVar + dwHTTP;
  146. PSTR pszEnd = strchr(pszStart,'\0');
  147. DWORD_PTR dwLen = pszEnd - pszStart;
  148. if (dwLen > 1)
  149. {
  150. DWORD dwOutLen = 0;
  151. PSTR pszHeader = m_bufRequest.Headers();
  152. do
  153. {
  154. if (GetVariableStrCmp(pszHeader,pszStart,dwLen))
  155. {
  156. pszHeader += dwLen+1; // skip past header + ':'
  157. while ( (pszHeader)[0] != '\0' && ((pszHeader[0] == ' ') ||
  158. (pszHeader[0] == '\t')))
  159. {
  160. ++(pszHeader);
  161. }
  162. pszTrav = strstr(pszHeader,"\r\n");
  163. if (pszTrav)
  164. {
  165. chSave = '\r';
  166. *pszTrav = 0;
  167. pszRet = pszHeader;
  168. }
  169. break;
  170. }
  171. pszHeader = strstr(pszHeader,"\r\n")+2;
  172. if (*pszHeader == '\r')
  173. {
  174. DEBUGCHK(*(pszHeader+1) == '\n');
  175. break;
  176. }
  177. } while (1);
  178. }
  179. }
  180. // end of pseudo-case stmnt
  181. if ((PSTR)(-1) == pszRet)
  182. {
  183. // unknown var
  184. SetLastError(ERROR_INVALID_INDEX);
  185. return FALSE;
  186. }
  187. // no such header/value. return empty (not NULL!) string
  188. if (!pszRet)
  189. pszRet = (PSTR)cszEmpty;
  190. if ((dwLen = strlen(pszRet)+1) > *pdwOutSize)
  191. {
  192. *pdwOutSize = dwLen;
  193. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  194. if (pszTrav)
  195. *pszTrav = chSave;
  196. return FALSE;
  197. }
  198. // Change: Check is done here, not in ::GetServerVariable. Lets us get size
  199. // with out buf = NULL
  200. if (NULL == pvOutBuf)
  201. {
  202. SetLastError(ERROR_INVALID_PARAMETER);
  203. return FALSE;
  204. }
  205. memcpy(pvOutBuf, pszRet, dwLen);
  206. if (pszTrav)
  207. *pszTrav = chSave;
  208. return TRUE;
  209. }
  210. BOOL CHttpRequest::WriteClientAsync(PVOID pvBuf, PDWORD pdwSize, BOOL fFromFilter)
  211. {
  212. BOOL ret = WriteClient(pvBuf, pdwSize, fFromFilter);
  213. if (m_pfnCompletion != NULL)
  214. {
  215. DWORD dwStatus;
  216. if (ret)
  217. dwStatus = ERROR_SUCCESS;
  218. else
  219. dwStatus = GetLastError();
  220. __try
  221. {
  222. (*m_pfnCompletion)(m_pECB, m_pvContext, *pdwSize, dwStatus);
  223. }
  224. __except(1) // catch all errors
  225. {
  226. TraceTag(ttidWebServer, "ISAPI I/O completion callback caused exception 0x%08x and was terminated", GetExceptionCode());
  227. g_pVars->m_pLog->WriteEvent(IDS_HTTPD_EXT_EXCEPTION,m_wszPath,GetExceptionCode(),L"IOCompletionProc",GetLastError());
  228. }
  229. }
  230. return ret;
  231. }
  232. BOOL CHttpRequest::WriteClient(PVOID pvBuf, PDWORD pdwSize, BOOL fFromFilter)
  233. {
  234. int cbSendBuf = *pdwSize;
  235. PSTR pszSendBuf = (PSTR) pvBuf;
  236. BOOL ret = FALSE;
  237. // On a HEAD request to an ASP page or ISAPI extension results in no data
  238. // being sent back, however for filters we do send data back when they
  239. // tell us to with WriteClient call.
  240. if (m_idMethod == TOK_HEAD && !fFromFilter)
  241. {
  242. ret = TRUE;
  243. goto done;
  244. }
  245. // are we buffering? Note: Only ASP can set this
  246. if (m_fBufferedResponse)
  247. {
  248. return m_bufRespBody.AppendData((PSTR) pvBuf, (int) *pdwSize);
  249. }
  250. if (g_pVars->m_fFilters &&
  251. ! CallFilter(SF_NOTIFY_SEND_RAW_DATA, &pszSendBuf, &cbSendBuf))
  252. goto done;
  253. if (cbSendBuf != send(m_socket, pszSendBuf, cbSendBuf, 0))
  254. {
  255. TraceTag(ttidWebServer, "HTTPD: SendBuffer FAILED. GLE=%d", GetLastError());
  256. goto done;
  257. }
  258. ret = TRUE;
  259. done:
  260. return ret;
  261. }
  262. // Acts as the custom header class (for Filters call to AddHeader, SetHeader
  263. // and for ASP Call to AddHeader and for ASP Cookie handler.
  264. // We made this function part of the class because there's no reason to memcpy
  265. // data into a temp buffer before memcpy'ing it into the real buffer.
  266. BOOL CBuffer::AddHeader(PSTR pszName, PSTR pszValue, BOOL fAddColon)
  267. {
  268. DEBUG_CODE_INIT;
  269. BOOL ret = FALSE;
  270. PSTR pszTrav;
  271. if (!pszName || !pszValue)
  272. {
  273. DEBUGCHK(0);
  274. return FALSE;
  275. }
  276. int cbName = strlen(pszName);
  277. int cbValue = strlen(pszValue);
  278. // we need a buffer size of pszName + pszValue, a space, a trailing \r\n, and \0
  279. int cbTotal = cbName + cbValue + sizeof("\r\n") + (fAddColon ? 1 : 0);
  280. if ( ! AllocMem( cbTotal ))
  281. myleave(900);
  282. pszTrav = m_pszBuf + m_iNextIn;
  283. memcpy(pszTrav, pszName, cbName);
  284. pszTrav += cbName;
  285. // put space between name and value and colon if needed.
  286. if (fAddColon)
  287. *pszTrav++ = ':';
  288. *pszTrav++ = ' ';
  289. memcpy(pszTrav, pszValue, cbValue);
  290. memcpy(pszTrav + cbValue,"\r\n", sizeof("\r\n"));
  291. m_iNextIn += cbTotal;
  292. ret = TRUE;
  293. done:
  294. TraceTag(ttidWebServer, "HTTPD: CBuffer::AddHeader failed, err = %d",err);
  295. return ret;
  296. }