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.

463 lines
15 KiB

  1. /*--
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name: CONNECT.CPP
  4. Author: Arul Menezes
  5. Abstract: All the constant data used by the HTTP daemon
  6. --*/
  7. #include "pch.h"
  8. #pragma hdrstop
  9. #include "httpd.h"
  10. const char* rgWkday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0};
  11. const char* rgMonth[] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};
  12. const char cszServerID[] = "UPnP/1.0";
  13. const char cszProductID[] = "UPnP Device Host/1.0";
  14. // const char cszRespStatus[] = "HTTP/1.0 %d %s\r\n";
  15. const char cszRespStatus[] = "HTTP/1.0 ";
  16. // const char cszRespServer[] = "Server: %s\r\n";
  17. const char cszRespServer2[] = "Server: ";
  18. // const char cszRespType[] = "Content-Type: %s\r\n";
  19. const char cszRespType2[] = "Content-Type: ";
  20. // const char cszRespLength[] = "Content-Length: %d\r\n";
  21. const char cszRespLength2[] = "Content-Length: ";
  22. // const char cszRespWWWAuthBasic[] = "WWW-Authenticate: Basic\r\n";
  23. const char cszRespWWWAuthBasic2[] = "WWW-Authenticate: Basic";
  24. const char cszRespWWWAuthNTLM[] = "WWW-Authenticate: NTLM";
  25. // const char cszDateFmt[] = "%3s, %02d %3s %04d %02d:%02d:%02d GMT\r\n";
  26. const char cszRespDate[] = "Date: ";
  27. // const char cszRespLocation[]="Location: %s\r\n";
  28. const char cszRespLocation2[]="Location: ";
  29. // const char cszConnection[] = "Connection: %s\r\n";
  30. const char cszConnection2[] = "Connection: ";
  31. const char cszKeepAlive[] = "keep-alive";
  32. const char cszClose[] = "close";
  33. const char cszCRLF[] = "\r\n";
  34. const char cszRespLastMod[] = "Last-Modified: ";
  35. #define APPENDCRLF(psz) { *psz++ = '\r'; *psz++ = '\n'; }
  36. // The order of items in this table must match that in enum RESPONSESTATUS
  37. // This is not international safe! In new version, we fill the table on
  38. // httpd initialization with string from the rc file.
  39. /*
  40. STATUSINFO rgStatus[STATUS_MAX] = {
  41. { 200, "OK", NULL },
  42. { 302, "Object Moved", "<head><title>Object Moved</title></head><body><h1>Object Moved</h1>This object has moved to "},
  43. { 304, "Not Modified", NULL }, // body not allowed for 304
  44. { 400, "Bad Request", "The request was not understood" },
  45. { 401, "Unauthorized", "Access denied" },
  46. { 403, "Forbidden", "Access denied" },
  47. { 404, "Object Not Found", "The requested URL was not found" },
  48. { 500, "Internal Server Error", "The server encountered an error" },
  49. { 501, "Not Implemented", "This method is not implemented" },
  50. };
  51. */
  52. STATUSINFO rgStatus[STATUS_MAX] = {
  53. { 200, "OK", NULL}, // no body!
  54. { 301, "Object Moved", NULL},
  55. { 304, "Not Modified", NULL}, // body not allowed for 304
  56. { 400, "Bad Request", NULL},
  57. { 401, "Unauthorized", NULL},
  58. { 403, "Forbidden", NULL},
  59. { 404, "Object Not Found", NULL},
  60. { 500, "Internal Server Error", NULL},
  61. { 501, "Not Implemented", NULL},
  62. { 505, "HTTP Version Not Supported", NULL},
  63. };
  64. #define LCID_USA MAKELANGID(LAND_ENGLISH, SUBLANG_ENGLISH_US);
  65. int SendData(SOCKET sock, const char FAR *pszBuffData, int cbBuffLen, int flags)
  66. {
  67. // assumption - sock is a blocking one
  68. char FAR *pszTempBuff ;
  69. int nBytesSent = 0;
  70. int retVal = cbBuffLen ;
  71. pszTempBuff = (char FAR*)pszBuffData ;
  72. while ( cbBuffLen > 0 )
  73. {
  74. if((nBytesSent = send(sock, pszTempBuff, cbBuffLen, flags)) == SOCKET_ERROR)
  75. {
  76. retVal = SOCKET_ERROR;
  77. TraceTag(ttidWebServer, "Send RESPONSE Data failed! - %d",WSAGetLastError());
  78. break;
  79. }
  80. if( nBytesSent <= 0 )
  81. { // XXX it may be that nBytesSent is zero. There is no simple solution other than
  82. // doing a select until the socket becomes writeable. For now, we want to make
  83. // sure that we make progress in the loop and ensure termination, so we will
  84. // just break out if this happens.
  85. retVal = SOCKET_ERROR;
  86. TraceTag(ttidWebServer, "Send RESPONSE Data failed! zero bytes sent - %d",WSAGetLastError());
  87. break;
  88. }
  89. cbBuffLen -= nBytesSent;
  90. pszTempBuff += nBytesSent;
  91. }
  92. return retVal;
  93. }
  94. void CHttpResponse::SendHeaders(PCSTR pszExtraHeaders, PCSTR pszNewRespStatus)
  95. {
  96. DEBUG_CODE_INIT;
  97. CHAR szBuf[HEADERBUFSIZE];
  98. PSTR pszBuf = szBuf;
  99. PSTR pszTrav;
  100. int iLen;
  101. DWORD cbNeeded ;
  102. PSTR pszFilterHeaders = NULL;
  103. if ( g_pVars->m_fFilters &&
  104. ! m_pRequest->CallFilter(SF_NOTIFY_SEND_RESPONSE))
  105. myleave(97);
  106. // For HTTP 0.9, we don't send headers back.
  107. if (m_pRequest->m_dwVersion <= MAKELONG(9, 0))
  108. myleave(0);
  109. // We do calculation up front to see if we need a allocate a buffer or not.
  110. // Certain may be set by an ISAPI Extension, Filter, or ASP
  111. // and we must do the check to make sure their sum plus http headers server
  112. // uses will be less than buffer we created.
  113. cbNeeded = m_pRequest->m_bufRespHeaders.Count() +
  114. MyStrlenA(pszExtraHeaders) +
  115. MyStrlenA(pszNewRespStatus) +
  116. MyStrlenA(m_pszRedirect) +
  117. MyStrlenA(m_pRequest->m_pszNTLMOutBuf) +
  118. ((m_pRequest->m_pFInfo && m_rs == STATUS_UNAUTHORIZED) ?
  119. MyStrlenA(m_pRequest->m_pFInfo->m_pszDenyHeader) : 0);
  120. // If what we need for extra + 1000 bytes (for the regular Http headers) is
  121. // > our buf, allocate a new one
  122. if (cbNeeded + 1000 > HEADERBUFSIZE)
  123. {
  124. if (!(pszBuf = MyRgAllocNZ(CHAR,cbNeeded+1000)))
  125. myleave(98);
  126. }
  127. pszTrav = pszBuf;
  128. // if (pszNewRespStatus)
  129. // iLen = sprintf(szBuf,"HTTP/1.0 %s\r\n",pszNewRespStatus);
  130. // else
  131. // iLen = sprintf(szBuf, cszRespStatus, rgStatus[m_rs].dwStatusNumber, rgStatus[m_rs].pszStatusText);
  132. // the status line
  133. // ServerSupportFunction on SEND_RESPONSE_HEADER can override the server value
  134. pszTrav = strcpyEx(pszTrav,cszRespStatus);
  135. if (pszNewRespStatus)
  136. {
  137. pszTrav = strcpyEx(pszTrav,pszNewRespStatus);
  138. }
  139. else // copy the number and value over
  140. {
  141. _itoa(rgStatus[m_rs].dwStatusNumber,pszTrav,10);
  142. pszTrav = strchr(pszTrav,'\0');
  143. *pszTrav++ = ' ';
  144. pszTrav = strcpyEx(pszTrav,rgStatus[m_rs].pszStatusText);
  145. }
  146. APPENDCRLF(pszTrav);
  147. // GENERAL HEADERS
  148. // the Date line
  149. SYSTEMTIME st;
  150. GetSystemTime(&st); // NOTE: Must be GMT!
  151. // iLen += sprintf(szBuf+iLen, cszDateFmt, rgWkday[st.wDayOfWeek], st.wDay, rgMonth[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
  152. pszTrav = strcpyEx(pszTrav, cszRespDate);
  153. pszTrav = WriteHTTPDate(pszTrav,&st,TRUE);
  154. // APPENDCRLF(pszTrav);
  155. // Connection: header
  156. if (m_connhdr != CONN_NONE)
  157. {
  158. // iLen += sprintf(szBuf+iLen, cszConnection, (m_connhdr==CONN_KEEP ? cszKeepAlive : cszClose));
  159. pszTrav = strcpyEx(pszTrav,cszConnection2);
  160. pszTrav = strcpyEx(pszTrav,(m_connhdr==CONN_KEEP ? cszKeepAlive : cszClose));
  161. APPENDCRLF(pszTrav);
  162. }
  163. // RESPONSE HEADERS
  164. // the server line
  165. // iLen += sprintf(szBuf+iLen, cszRespServer, cszServerID);
  166. pszTrav = strcpyEx(pszTrav,cszRespServer2);
  167. pszTrav = strcpyEx(pszTrav,g_pVars->m_pszServerID);
  168. APPENDCRLF(pszTrav);
  169. // the Location header (for redirects)
  170. if (m_pszRedirect)
  171. {
  172. DEBUGCHK(m_rs == STATUS_MOVED);
  173. // iLen += sprintf(szBuf+iLen, cszRespLocation, m_pszRedirect);
  174. pszTrav = strcpyEx(pszTrav,cszRespLocation2);
  175. pszTrav = strcpyEx(pszTrav,m_pszRedirect);
  176. APPENDCRLF(pszTrav);
  177. }
  178. // the WWW-Authenticate line
  179. if (m_rs == STATUS_UNAUTHORIZED)
  180. {
  181. // In the middle of an NTLM authentication session
  182. if (g_pVars->m_fNTLMAuth && m_pRequest->m_pszNTLMOutBuf)
  183. {
  184. // iLen += sprintf(szBuf+iLen,"%s %s\r\n",cszRespWWWAuthNTLM,m_pRequest->m_pszNTLMOutBuf);
  185. pszTrav = strcpyEx(pszTrav,cszRespWWWAuthNTLM);
  186. *pszTrav++ = ' ';
  187. pszTrav = strcpyEx(pszTrav,m_pRequest->m_pszNTLMOutBuf);
  188. APPENDCRLF(pszTrav);
  189. }
  190. // If both schemes are enabled, send both back to client and let the browser decide which to use
  191. else if (g_pVars->m_fBasicAuth && g_pVars->m_fNTLMAuth)
  192. {
  193. // iLen += sprintf(szBuf+iLen,"%s\r\n%s",cszRespWWWAuthNTLM,cszRespWWWAuthBasic);
  194. pszTrav = strcpyEx(pszTrav,cszRespWWWAuthNTLM);
  195. APPENDCRLF(pszTrav);
  196. pszTrav = strcpyEx(pszTrav,cszRespWWWAuthBasic2);
  197. APPENDCRLF(pszTrav);
  198. }
  199. else if (g_pVars->m_fBasicAuth)
  200. {
  201. // iLen += sprintf(szBuf+iLen, cszRespWWWAuthBasic);
  202. pszTrav = strcpyEx(pszTrav,cszRespWWWAuthBasic2);
  203. APPENDCRLF(pszTrav);
  204. }
  205. else if (g_pVars->m_fNTLMAuth)
  206. {
  207. // iLen += sprintf(szBuf+iLen,"%s\r\n",cszRespWWWAuthNTLM);
  208. pszTrav = strcpyEx(pszTrav,cszRespWWWAuthNTLM);
  209. APPENDCRLF(pszTrav);
  210. }
  211. }
  212. // ENTITY HEADERS
  213. // the Last-Modified line
  214. if (m_hFile)
  215. {
  216. FILETIME ft;
  217. SYSTEMTIME st;
  218. if ( GetFileTime(m_hFile, NULL, NULL, &ft) && // gets filetime in GMT
  219. FileTimeToSystemTime(&ft, &st) ) // converts GMT filetime to GMT systemtime
  220. {
  221. // iLen += sprintf(szBuf+iLen, cszDateFmt, rgWkday[st.wDayOfWeek], st.wDay, rgMonth[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
  222. pszTrav = strcpyEx(pszTrav, cszRespLastMod);
  223. pszTrav = WriteHTTPDate(pszTrav,&st,TRUE);
  224. }
  225. }
  226. // the Content-Type line
  227. if (m_pszType)
  228. {
  229. // iLen += sprintf(szBuf+iLen, cszRespType, m_pszType);
  230. pszTrav = strcpyEx(pszTrav,cszRespType2);
  231. pszTrav = strcpyEx(pszTrav,m_pszType);
  232. APPENDCRLF(pszTrav);
  233. }
  234. // the Content-Length line
  235. if (m_dwLength)
  236. {
  237. // If we have a file that is 0 length, it is set to -1.
  238. if (m_dwLength == -1)
  239. m_dwLength = 0;
  240. // iLen += sprintf(szBuf+iLen, cszRespLength, m_dwLength);
  241. pszTrav = strcpyEx(pszTrav,cszRespLength2);
  242. _itoa(m_dwLength,pszTrav,10);
  243. pszTrav = strchr(pszTrav,'\0');
  244. APPENDCRLF(pszTrav);
  245. }
  246. if ((m_rs == STATUS_UNAUTHORIZED) && m_pRequest->m_pFInfo && m_pRequest->m_pFInfo->m_pszDenyHeader)
  247. {
  248. pszTrav = strcpyEx(pszTrav,m_pRequest->m_pFInfo->m_pszDenyHeader);
  249. // It's the script's responsibility to add any \r\n to the headers.
  250. }
  251. if (m_pRequest->m_bufRespHeaders.Data())
  252. {
  253. memcpy(pszTrav,m_pRequest->m_bufRespHeaders.Data(),m_pRequest->m_bufRespHeaders.Count());
  254. pszTrav += m_pRequest->m_bufRespHeaders.Count();
  255. }
  256. // APPENDCRLF(pszTrav);
  257. if (pszExtraHeaders)
  258. {
  259. pszTrav = strcpyEx(pszTrav,pszExtraHeaders);
  260. // It's the script's responsibility to add any \r\n to the headers.
  261. }
  262. else
  263. {
  264. APPENDCRLF(pszTrav); // the double CRLF signifies that header data is at an end
  265. }
  266. *pszTrav = 0;
  267. pszFilterHeaders = pszBuf; // pointer may be modified, don't loose original pszBuf ptr
  268. iLen = (int)((INT_PTR)(pszTrav - pszBuf));
  269. if (g_pVars->m_fFilters &&
  270. ! m_pRequest->CallFilter(SF_NOTIFY_SEND_RAW_DATA, &pszFilterHeaders, &iLen))
  271. myleave(99);
  272. iLen = SendData(m_socket,pszFilterHeaders,iLen,0);
  273. done:
  274. TraceTag(ttidWebServer, "Sending RESPONSE HEADER<<%s>>", pszFilterHeaders);
  275. if (pszBuf != szBuf)
  276. MyFree(pszBuf);
  277. }
  278. void CHttpResponse::SendBody(void)
  279. {
  280. if (TOK_HEAD == m_pRequest->m_idMethod)
  281. return;
  282. if (m_hFile)
  283. SendFile(m_socket, m_hFile, m_pRequest);
  284. else if (m_pszBody)
  285. {
  286. PSTR pszSendBuf = (PSTR) m_pszBody;
  287. int cbSendBuf = m_dwLength;
  288. if (g_pVars->m_fFilters &&
  289. ! m_pRequest->CallFilter(SF_NOTIFY_SEND_RAW_DATA, &pszSendBuf, &cbSendBuf))
  290. {
  291. ;
  292. }
  293. else
  294. { // send if there's no filters or if filter call succeeded
  295. SendData(m_socket, pszSendBuf, cbSendBuf, 0);
  296. }
  297. TraceTag(ttidWebServer, "Sending RESPONSE BODY<<%s>> len=%d", pszSendBuf, cbSendBuf);
  298. }
  299. }
  300. void SendFile(SOCKET sock, HANDLE hFile, CHttpRequest *pRequest)
  301. {
  302. BYTE bBuf[4096];
  303. DWORD dwRead;
  304. PBYTE pszSendBuf;
  305. int cbSendBuf;
  306. int nBytesSent = 0;
  307. while (ReadFile(hFile, bBuf, sizeof(bBuf), &dwRead, 0) && dwRead)
  308. {
  309. pszSendBuf = bBuf;
  310. cbSendBuf = dwRead;
  311. if (g_pVars->m_fFilters &&
  312. ! pRequest->CallFilter(SF_NOTIFY_SEND_RAW_DATA, (PSTR*) &pszSendBuf, &cbSendBuf))
  313. {
  314. ;
  315. }
  316. else
  317. { // send if there's no filters or if filter call succeeded
  318. if((nBytesSent = SendData(sock, (PSTR) pszSendBuf, cbSendBuf, 0)) == SOCKET_ERROR)
  319. {
  320. TraceTag(ttidWebServer, "Send RESPONSE Data failed! - %d",WSAGetLastError());
  321. break;
  322. }
  323. else
  324. {
  325. TraceTag(ttidWebServer, "Sending RESPONSE Data - Bytes to be sent = %d bytes sent = %d", dwRead, nBytesSent );
  326. }
  327. }
  328. }
  329. return;
  330. }
  331. // This function used to display the message "Object moved
  332. void CHttpResponse::SendRedirect(PCSTR pszRedirect, BOOL fFromFilter)
  333. {
  334. if (!fFromFilter && m_pRequest->FilterNoResponse())
  335. return;
  336. DEBUGCHK(!m_hFile);
  337. DEBUGCHK(m_rs==STATUS_MOVED);
  338. // create a body
  339. PSTR pszBody = MySzAllocA(strlen(rgStatus[m_rs].pszStatusBody)+2*strlen(pszRedirect)+30);
  340. DWORD dwLen = 0;
  341. if (pszBody)
  342. {
  343. // originally used this string set -- "Moved Permanently", "<head><title>Object Moved</title></head><body><h1>Object Moved</h1>This object has moved to <a HREF=\"%s\">%s</a></body>" },
  344. // sprintf(pszBody, rgStatus[m_rs].pszStatusBody, pszRedirect, pszRedirect);
  345. PSTR pszTrav = strcpyEx(pszBody,rgStatus[m_rs].pszStatusBody);
  346. pszTrav = strcpyEx(pszTrav,"<a href=\"");
  347. pszTrav = strcpyEx(pszTrav,pszRedirect);
  348. pszTrav = strcpyEx(pszTrav,"\">");
  349. pszTrav = strcpyEx(pszTrav,pszRedirect);
  350. pszTrav = strcpyEx(pszTrav,"</a></body>");
  351. SetBody(pszBody, cszTextHtml);
  352. }
  353. // set redirect header & send all headers, then the synthetic body
  354. m_pszRedirect = pszRedirect;
  355. SendHeaders(NULL,NULL);
  356. SendBody();
  357. MyFree(pszBody);
  358. }
  359. // Read strings of the bodies to send on web server errors ("Object not found",
  360. // "Server Error",...) using load string. These strings are in wide character
  361. // format, so we first convert them to regular strings, marching along
  362. // pszBodyCodes (which is a buffer size BODYSTRINGSIZE). After the conversion,
  363. // we set each rgStatus[i].pszStatusBody to the pointer in the buffer.
  364. void InitializeResponseCodes(PSTR pszStatusBodyBuf)
  365. {
  366. PSTR pszTrav = pszStatusBodyBuf;
  367. UINT i;
  368. int iLen;
  369. WCHAR wszBuf[256];
  370. for (i = 0; i < ARRAYSIZEOF(rgStatus); i++)
  371. {
  372. // no bodies for these
  373. if (i == STATUS_OK || i == STATUS_NOTMODIFIED)
  374. continue;
  375. LoadString(g_hInst,RESBASE_body + i,wszBuf,celems(wszBuf));
  376. iLen = MyW2A(wszBuf, pszTrav, BODYSTRINGSIZE - (int)((INT_PTR)((pszTrav - pszStatusBodyBuf))));
  377. if (!iLen)
  378. return;
  379. rgStatus[i].pszStatusBody = pszTrav;
  380. pszTrav += iLen;
  381. }
  382. }