Leaked source code of windows server 2003
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.

374 lines
11 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. send.cxx
  5. Abstract:
  6. This file contains the HTTP Request Handle Object SendRequest method
  7. Contents:
  8. CFsm_SendRequest::RunSM
  9. HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm
  10. Author:
  11. Keith Moore (keithmo) 16-Nov-1994
  12. Revision History:
  13. 29-Apr-97 rfirth
  14. Conversion to FSM
  15. --*/
  16. #include <wininetp.h>
  17. #include <perfdiag.hxx>
  18. #include "httpp.h"
  19. //
  20. // HTTP Request Handle Object methods
  21. //
  22. DWORD
  23. CFsm_SendRequest::RunSM(
  24. IN CFsm * Fsm
  25. )
  26. /*++
  27. Routine Description:
  28. description-of-function.
  29. Arguments:
  30. Fsm -
  31. Return Value:
  32. DWORD
  33. --*/
  34. {
  35. DEBUG_ENTER((DBG_HTTP,
  36. Dword,
  37. "CFsm_SendRequest::RunSM",
  38. "%#x",
  39. Fsm
  40. ));
  41. START_SENDREQ_PERF();
  42. CFsm_SendRequest * stateMachine = (CFsm_SendRequest *)Fsm;
  43. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  44. DWORD error;
  45. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  46. switch (Fsm->GetState()) {
  47. case FSM_STATE_INIT:
  48. case FSM_STATE_CONTINUE:
  49. error = pRequest->SendRequest_Fsm(stateMachine);
  50. break;
  51. default:
  52. error = ERROR_WINHTTP_INTERNAL_ERROR;
  53. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  54. INET_ASSERT(FALSE);
  55. break;
  56. }
  57. DEBUG_LEAVE(error);
  58. STOP_SENDREQ_PERF();
  59. return error;
  60. }
  61. DWORD
  62. HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm(
  63. IN CFsm_SendRequest * Fsm
  64. )
  65. /*++
  66. Routine Description:
  67. description-of-function.
  68. Arguments:
  69. Fsm -
  70. Return Value:
  71. DWORD
  72. --*/
  73. {
  74. DEBUG_ENTER((DBG_HTTP,
  75. Dword,
  76. "HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm",
  77. "%#x",
  78. Fsm
  79. ));
  80. PERF_ENTER(SendRequest_Fsm);
  81. CFsm_SendRequest & fsm = *Fsm;
  82. DWORD error = fsm.GetError();
  83. FSM_STATE state = fsm.GetState();
  84. LPSTR requestBuffer = fsm.m_pRequestBuffer;
  85. DWORD requestLength = fsm.m_dwRequestLength;
  86. LPVOID lpOptional = fsm.m_lpOptional;
  87. DWORD dwOptionalLength = fsm.m_dwOptionalLength;
  88. BOOL bExtraCrLf = fsm.m_bExtraCrLf;
  89. if (error != ERROR_SUCCESS) {
  90. goto quit;
  91. }
  92. if (state != FSM_STATE_INIT) {
  93. state = fsm.GetFunctionState();
  94. }
  95. switch (state) {
  96. case FSM_STATE_INIT:
  97. fsm.SetFunctionState(FSM_STATE_1);
  98. error = DoFsm(New CFsm_MakeConnection(this));
  99. case FSM_STATE_1:
  100. if ((error != ERROR_SUCCESS)
  101. || ((GetStatusCode() != HTTP_STATUS_OK) && (GetStatusCode() != 0))) {
  102. goto quit;
  103. }
  104. // Monolithic upload: If we have optional data to send,
  105. // save off in handle and flag that the data has been saved.
  106. // This is useful in the case of redirects and auth, because of RR FSM changes:
  107. if (fsm.m_lpOptional && fsm.m_dwOptionalLength)
  108. {
  109. _lpOptionalSaved = fsm.m_lpOptional;
  110. _dwOptionalSaved = fsm.m_dwOptionalLength;
  111. _fOptionalSaved = TRUE;
  112. }
  113. else
  114. // Check if optional data has been saved in handle during a previous
  115. // SendRequest or negotiate stage. If so, restore it and content length:
  116. // Do it only if you don't have something already:
  117. if (_fOptionalSaved)
  118. {
  119. // Restore the fsm optional values and content length.
  120. lpOptional = fsm.m_lpOptional = _lpOptionalSaved;
  121. dwOptionalLength = fsm.m_dwOptionalLength = _dwOptionalSaved;
  122. if(!IsWriteRequired())
  123. // Reset Content-Length, but only if Writes are not required. If Writes are required, someplace
  124. // else would have done it. In the case of redirects and auth, we should not hit this for Writes,
  125. // because we fail the request:
  126. {
  127. DWORD cbNumber;
  128. CHAR szNumber[sizeof("4294967295")];
  129. cbNumber = wsprintf(szNumber, "%d", fsm.m_dwOptionalLength);
  130. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  131. (LPSTR)szNumber,
  132. cbNumber,
  133. 0, // dwIndex
  134. ADD_HEADER
  135. );
  136. }
  137. }
  138. // # 62953
  139. // If initiating NTLM authentication, don't submit request data since
  140. // we're expecting to get a challenge and resubmit the request anyway.
  141. if (GetAuthState() == AUTHSTATE_NEGOTIATE)
  142. {
  143. if (!((PLUG_CTX*)(GetAuthCtx()))->_fNTLMProxyAuth)
  144. {
  145. // We are in the negotiate phase during a POST
  146. // and do not have an authenticated socket.
  147. // In both monolithic upload InternetWriteFile
  148. // cases, we wish to omit any post data, and reflect
  149. // this in the content length.
  150. if (!((GetMethodType() == HTTP_METHOD_TYPE_GET) && !IsMethodBody()))
  151. {
  152. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  153. "0",
  154. 1,
  155. 0, // dwIndex
  156. ADD_HEADER
  157. );
  158. }
  159. fsm.m_lpOptional = lpOptional = NULL;
  160. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  161. }
  162. }
  163. bExtraCrLf = (!(GetOpenFlags() & WINHTTP_FLAG_SECURE)
  164. && (dwOptionalLength != 0)
  165. && ((GetServerInfo() != NULL)
  166. ? GetServerInfo()->IsHttp1_0()
  167. : TRUE));
  168. //
  169. // collect request headers into blob
  170. //
  171. BOOL bCombinedData;
  172. requestBuffer = CreateRequestBuffer(&requestLength,
  173. lpOptional,
  174. dwOptionalLength,
  175. bExtraCrLf,
  176. GlobalTransportPacketLength,
  177. &bCombinedData
  178. );
  179. if (requestBuffer == NULL) {
  180. error = ERROR_NOT_ENOUGH_MEMORY;
  181. goto quit;
  182. }
  183. DEBUG_PRINT(HTTP, INFO, ("SendRequest_FSM: lpOptional=0x%x dwOptionalLength=%d\n",
  184. fsm.m_lpOptional, fsm.m_dwOptionalLength));
  185. if (bCombinedData) {
  186. //
  187. // everything copied to one buffer. No need to send separate
  188. // optional data and CR-LF termination
  189. //
  190. fsm.m_lpOptional = lpOptional = NULL;
  191. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  192. bExtraCrLf = FALSE;
  193. }
  194. fsm.m_pRequestBuffer = requestBuffer;
  195. fsm.m_dwRequestLength = requestLength;
  196. fsm.m_bExtraCrLf = bExtraCrLf;
  197. DEBUG_PRINT(HTTP, INFO, ("fsm.m_pRequestBuffer=0x%x\r\n", fsm.m_pRequestBuffer));
  198. StartRTT();
  199. //
  200. // send the request. If we are using a keep-alive connection, this may
  201. // fail because the server timed it out since we last used it. We must
  202. // be prepared to re-establish
  203. //
  204. fsm.SetFunctionState(FSM_STATE_3);
  205. error = _Socket->Send(requestBuffer, requestLength, SF_INDICATE);
  206. //
  207. // fall through
  208. //
  209. case FSM_STATE_3:
  210. if (error != ERROR_SUCCESS) {
  211. if (error != ERROR_IO_PENDING) {
  212. CloseConnection(TRUE);
  213. }
  214. goto quit;
  215. }
  216. //
  217. // send any optional data (that we didn't send in the request buffer).
  218. // If this fails then we don't retry. We assume that if the first send
  219. // succeedeed, but the second failed, then this is a non-recoverable
  220. // error
  221. //
  222. //fsm.m_bExtraCrLf = bExtraCrLf = TRUE;
  223. if (dwOptionalLength != 0) {
  224. LPSTR buffer = (LPSTR)lpOptional;
  225. DWORD length = dwOptionalLength;
  226. if (bExtraCrLf) {
  227. length += sizeof(gszCRLF) - 1;
  228. if (requestLength >= length) {
  229. buffer = requestBuffer;
  230. } else if (length <= GlobalTransportPacketLength) {
  231. requestBuffer = (LPSTR)ResizeBuffer(requestBuffer,
  232. length,
  233. FALSE
  234. );
  235. buffer = requestBuffer;
  236. fsm.m_pRequestBuffer = requestBuffer;
  237. } else {
  238. length -= sizeof(gszCRLF) - 1;
  239. }
  240. if (buffer == requestBuffer) {
  241. memcpy(buffer, lpOptional, dwOptionalLength);
  242. buffer[dwOptionalLength] = '\r';
  243. buffer[dwOptionalLength + 1] = '\n';
  244. fsm.m_bExtraCrLf = bExtraCrLf = FALSE;
  245. }
  246. }
  247. fsm.SetFunctionState(FSM_STATE_4);
  248. error = _Socket->Send(buffer, length, SF_INDICATE);
  249. }
  250. //
  251. // fall through
  252. //
  253. case FSM_STATE_4:
  254. //
  255. // Here we also add an extra CR-LF if the app is sending data (even if
  256. // the amount of data supplied is zero) unless we are using a keep-alive
  257. // connection, in which case we're not dealing with old servers which
  258. // require CR-LF at the end of post data.
  259. //
  260. // But only do this for non-HTTP 1.1 servers and proxies ( ie when
  261. // the user puts us in HTTP 1.0 mode)
  262. //
  263. if ((error == ERROR_SUCCESS) && bExtraCrLf) {
  264. fsm.SetFunctionState(FSM_STATE_5);
  265. error = _Socket->Send(gszCRLF, 2, SF_INDICATE);
  266. }
  267. //
  268. // fall through
  269. //
  270. case FSM_STATE_5:
  271. //
  272. // we are now in receiving state
  273. //
  274. if (error == ERROR_SUCCESS) {
  275. SetState(HttpRequestStateResponse);
  276. }
  277. break;
  278. }
  279. quit:
  280. if (error != ERROR_IO_PENDING) {
  281. //dprintf("HTTP connect-send took %d msec\n", GetTickCount() - _dwQuerySetCookieHeader);
  282. fsm.SetDone();
  283. PERF_LEAVE(SendRequest_Fsm);
  284. }
  285. DEBUG_LEAVE(error);
  286. return error;
  287. }