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.

332 lines
8.9 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. case FSM_STATE_ERROR:
  52. error = Fsm->GetError();
  53. INET_ASSERT (error == ERROR_WINHTTP_OPERATION_CANCELLED);
  54. Fsm->SetDone();
  55. break;
  56. default:
  57. error = ERROR_WINHTTP_INTERNAL_ERROR;
  58. Fsm->SetDone(ERROR_WINHTTP_INTERNAL_ERROR);
  59. INET_ASSERT(FALSE);
  60. break;
  61. }
  62. DEBUG_LEAVE(error);
  63. STOP_SENDREQ_PERF();
  64. return error;
  65. }
  66. DWORD
  67. HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm(
  68. IN CFsm_SendRequest * Fsm
  69. )
  70. /*++
  71. Routine Description:
  72. description-of-function.
  73. Arguments:
  74. Fsm -
  75. Return Value:
  76. DWORD
  77. --*/
  78. {
  79. DEBUG_ENTER((DBG_HTTP,
  80. Dword,
  81. "HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm",
  82. "%#x",
  83. Fsm
  84. ));
  85. PERF_ENTER(SendRequest_Fsm);
  86. CFsm_SendRequest & fsm = *Fsm;
  87. DWORD error = fsm.GetError();
  88. FSM_STATE state = fsm.GetState();
  89. LPSTR requestBuffer = fsm.m_pRequestBuffer;
  90. DWORD requestLength = fsm.m_dwRequestLength;
  91. LPVOID lpOptional = fsm.m_lpOptional;
  92. DWORD dwOptionalLength = fsm.m_dwOptionalLength;
  93. if (error != ERROR_SUCCESS) {
  94. goto quit;
  95. }
  96. if (state != FSM_STATE_INIT) {
  97. state = fsm.GetFunctionState();
  98. }
  99. switch (state) {
  100. case FSM_STATE_INIT:
  101. fsm.SetFunctionState(FSM_STATE_1);
  102. error = DoFsm(New CFsm_MakeConnection(this));
  103. case FSM_STATE_1:
  104. if ((error != ERROR_SUCCESS)
  105. || ((GetStatusCode() != HTTP_STATUS_OK) && (GetStatusCode() != 0))) {
  106. goto quit;
  107. }
  108. // Monolithic upload: If we have optional data to send,
  109. // save off in handle and flag that the data has been saved.
  110. // This is useful in the case of redirects and auth, because of RR FSM changes:
  111. if (fsm.m_lpOptional && fsm.m_dwOptionalLength)
  112. {
  113. _lpOptionalSaved = fsm.m_lpOptional;
  114. _dwOptionalSaved = fsm.m_dwOptionalLength;
  115. _fOptionalSaved = TRUE;
  116. }
  117. else
  118. // Check if optional data has been saved in handle during a previous
  119. // SendRequest or negotiate stage. If so, restore it and content length:
  120. // Do it only if you don't have something already:
  121. if (_fOptionalSaved)
  122. {
  123. // Restore the fsm optional values and content length.
  124. lpOptional = fsm.m_lpOptional = _lpOptionalSaved;
  125. dwOptionalLength = fsm.m_dwOptionalLength = _dwOptionalSaved;
  126. if(!IsWriteRequired())
  127. // Reset Content-Length, but only if Writes are not required. If Writes are required, someplace
  128. // else would have done it. In the case of redirects and auth, we should not hit this for Writes,
  129. // because we fail the request:
  130. {
  131. DWORD cbNumber;
  132. CHAR szNumber[sizeof("4294967295")];
  133. cbNumber = wsprintf(szNumber, "%u", fsm.m_dwOptionalLength);
  134. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  135. (LPSTR)szNumber,
  136. cbNumber,
  137. 0, // dwIndex
  138. ADD_HEADER
  139. );
  140. }
  141. }
  142. // # 62953
  143. // If initiating NTLM authentication, don't submit request data since
  144. // we're expecting to get a challenge and resubmit the request anyway.
  145. if (GetAuthState() == AUTHSTATE_NEGOTIATE)
  146. {
  147. // We are in the negotiate phase during a POST
  148. // and do not have an authenticated socket.
  149. // In both monolithic upload InternetWriteFile
  150. // cases, we wish to omit any post data, and reflect
  151. // this in the content length.
  152. if (!((GetMethodType() == HTTP_METHOD_TYPE_GET) && !IsMethodBody()))
  153. {
  154. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  155. "0",
  156. 1,
  157. 0, // dwIndex
  158. ADD_HEADER
  159. );
  160. }
  161. fsm.m_lpOptional = lpOptional = NULL;
  162. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  163. }
  164. //
  165. // collect request headers into blob
  166. //
  167. BOOL bCombinedData;
  168. requestBuffer = CreateRequestBuffer(&requestLength,
  169. lpOptional,
  170. dwOptionalLength,
  171. GlobalTransportPacketLength,
  172. &bCombinedData
  173. );
  174. if (requestBuffer == NULL) {
  175. error = ERROR_NOT_ENOUGH_MEMORY;
  176. goto quit;
  177. }
  178. DEBUG_PRINT(HTTP, INFO, ("SendRequest_FSM: lpOptional=0x%x dwOptionalLength=%d\n",
  179. fsm.m_lpOptional, fsm.m_dwOptionalLength));
  180. if (bCombinedData) {
  181. //
  182. // everything copied to one buffer. No need to send separate
  183. // optional data and CR-LF termination
  184. //
  185. fsm.m_lpOptional = lpOptional = NULL;
  186. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  187. }
  188. fsm.m_pRequestBuffer = requestBuffer;
  189. fsm.m_dwRequestLength = requestLength;
  190. DEBUG_PRINT(HTTP, INFO, ("fsm.m_pRequestBuffer=0x%x\r\n", fsm.m_pRequestBuffer));
  191. StartRTT();
  192. //
  193. // send the request. If we are using a keep-alive connection, this may
  194. // fail because the server timed it out since we last used it. We must
  195. // be prepared to re-establish
  196. //
  197. // if we are sending an "authorization" header, the "Send" operation could cause the socket
  198. // to be "tainted"; therefore if that's the case, we need to mark the socket as "authorized"
  199. // so that it can't go to the global keep-alive pool.
  200. if (IsAuthorized())
  201. {
  202. _Socket->SetAuthorized();
  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. if (dwOptionalLength != 0) {
  223. LPSTR buffer = (LPSTR)lpOptional;
  224. DWORD length = dwOptionalLength;
  225. fsm.SetFunctionState(FSM_STATE_4);
  226. error = _Socket->Send(buffer, length, SF_INDICATE);
  227. }
  228. //
  229. // fall through
  230. //
  231. case FSM_STATE_4:
  232. //
  233. // we are now in receiving state
  234. //
  235. if (error == ERROR_SUCCESS) {
  236. SetState(HttpRequestStateResponse);
  237. }
  238. break;
  239. }
  240. quit:
  241. if (error != ERROR_IO_PENDING) {
  242. //dprintf("HTTP connect-send took %d msec\n", GetTickCount() - _dwQuerySetCookieHeader);
  243. fsm.SetDone();
  244. PERF_LEAVE(SendRequest_Fsm);
  245. }
  246. DEBUG_LEAVE(error);
  247. return error;
  248. }