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.

392 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_INTERNET_INTERNAL_ERROR;
  53. Fsm->SetDone(ERROR_INTERNET_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. DEBUG_PRINT(
  105. HTTP,
  106. INFO,
  107. ("authstate=%x [%s]\n", GetAuthState(), InternetMapAuthState(GetAuthState()))
  108. );
  109. // # 62953
  110. // If initiating MSN or NTLM authentication, don't submit request data since
  111. // we're expecting to get a challenge and resubmit the request anyway.
  112. if (GetAuthState() == AUTHSTATE_NEGOTIATE)
  113. {
  114. if (!((PLUG_CTX*)(GetAuthCtx()))->_fNTLMProxyAuth
  115. && !(GetAuthCtx()->GetSchemeType() == AUTHCTX::SCHEME_DPA))
  116. {
  117. // We are in the negotiate phase during a POST
  118. // and do not have an authenticated socket.
  119. // In both monolithic upload InternetWriteFile
  120. // cases, we wish to omit any post data, and reflect
  121. // this in the content length.
  122. if (!((GetMethodType() == HTTP_METHOD_TYPE_GET) && !IsMethodBody()))
  123. {
  124. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  125. "0",
  126. 1,
  127. 0, // dwIndex
  128. ADD_HEADER
  129. );
  130. }
  131. // Monolithic upload: If we have optional data to send,
  132. // save off in handle and flag that the data has been saved.
  133. if (fsm.m_lpOptional && fsm.m_dwOptionalLength)
  134. {
  135. DEBUG_PRINT(
  136. HTTP,
  137. INFO,
  138. ("omitting request data due to authstate=%x [%s]\n", GetAuthState(), InternetMapAuthState(GetAuthState()))
  139. );
  140. _lpOptionalSaved = fsm.m_lpOptional;
  141. _dwOptionalSaved = fsm.m_dwOptionalLength;
  142. fsm.m_lpOptional = lpOptional = NULL;
  143. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  144. _fOptionalSaved = TRUE;
  145. }
  146. }
  147. }
  148. else
  149. {
  150. // Check if optional data has been saved in handle during a previous
  151. // negotiate stage. If so, restore it and content length and clear flag.
  152. if (_fOptionalSaved)
  153. {
  154. DEBUG_PRINT(
  155. HTTP,
  156. INFO,
  157. ("restoring request data due to authstate=%x [%s]\n", GetAuthState(), InternetMapAuthState(GetAuthState()))
  158. );
  159. // Reset the fsm optional values and content length.
  160. lpOptional = fsm.m_lpOptional = _lpOptionalSaved;
  161. dwOptionalLength = fsm.m_dwOptionalLength = _dwOptionalSaved;
  162. _dwOptionalSaved = 0;
  163. _lpOptionalSaved = NULL;
  164. _fOptionalSaved = FALSE;
  165. DWORD cbNumber;
  166. CHAR szNumber[sizeof("4294967295")];
  167. cbNumber = wsprintf(szNumber, "%d", fsm.m_dwOptionalLength);
  168. ReplaceRequestHeader(HTTP_QUERY_CONTENT_LENGTH,
  169. (LPSTR)szNumber,
  170. cbNumber,
  171. 0, // dwIndex
  172. ADD_HEADER
  173. );
  174. }
  175. }
  176. bExtraCrLf = (!(GetOpenFlags() & INTERNET_FLAG_SECURE)
  177. && (dwOptionalLength != 0)
  178. && ((GetServerInfo() != NULL)
  179. ? GetServerInfo()->IsHttp1_0()
  180. : IsRequestHttp1_0())
  181. && GlobalSendExtraCRLF);
  182. //
  183. // collect request headers into blob
  184. //
  185. BOOL bCombinedData;
  186. requestBuffer = CreateRequestBuffer(&requestLength,
  187. lpOptional,
  188. dwOptionalLength,
  189. bExtraCrLf,
  190. GlobalTransportPacketLength,
  191. &bCombinedData
  192. );
  193. if (requestBuffer == NULL) {
  194. error = ERROR_NOT_ENOUGH_MEMORY;
  195. goto quit;
  196. }
  197. DEBUG_PRINT(HTTP, INFO, ("SendRequest_FSM: lpOptional=0x%x dwOptionalLength=%d\n",
  198. fsm.m_lpOptional, fsm.m_dwOptionalLength));
  199. if (bCombinedData) {
  200. //
  201. // everything copied to one buffer. No need to send separate
  202. // optional data and CR-LF termination
  203. //
  204. fsm.m_lpOptional = lpOptional = NULL;
  205. fsm.m_dwOptionalLength = dwOptionalLength = 0;
  206. bExtraCrLf = FALSE;
  207. }
  208. fsm.m_pRequestBuffer = requestBuffer;
  209. fsm.m_dwRequestLength = requestLength;
  210. fsm.m_bExtraCrLf = bExtraCrLf;
  211. DEBUG_PRINT(HTTP, INFO, ("fsm.m_pRequestBuffer=0x%x\r\n", fsm.m_pRequestBuffer));
  212. StartRTT();
  213. //
  214. // send the request. If we are using a keep-alive connection, this may
  215. // fail because the server timed it out since we last used it. We must
  216. // be prepared to re-establish
  217. //
  218. fsm.SetFunctionState(FSM_STATE_3);
  219. error = _Socket->Send(requestBuffer, requestLength, SF_INDICATE);
  220. //
  221. // fall through
  222. //
  223. case FSM_STATE_3:
  224. if (error != ERROR_SUCCESS) {
  225. if (error != ERROR_IO_PENDING) {
  226. CloseConnection(TRUE);
  227. }
  228. goto quit;
  229. }
  230. //
  231. // send any optional data (that we didn't send in the request buffer).
  232. // If this fails then we don't retry. We assume that if the first send
  233. // succeedeed, but the second failed, then this is a non-recoverable
  234. // error
  235. //
  236. //fsm.m_bExtraCrLf = bExtraCrLf = TRUE;
  237. if (dwOptionalLength != 0) {
  238. LPSTR buffer = (LPSTR)lpOptional;
  239. DWORD length = dwOptionalLength;
  240. if (bExtraCrLf) {
  241. length += sizeof(gszCRLF) - 1;
  242. if (requestLength >= length) {
  243. buffer = requestBuffer;
  244. } else if (length <= GlobalTransportPacketLength) {
  245. requestBuffer = (LPSTR)ResizeBuffer(requestBuffer,
  246. length,
  247. FALSE
  248. );
  249. buffer = requestBuffer;
  250. fsm.m_pRequestBuffer = requestBuffer;
  251. } else {
  252. length -= sizeof(gszCRLF) - 1;
  253. }
  254. if (buffer == requestBuffer) {
  255. memcpy(buffer, lpOptional, dwOptionalLength);
  256. buffer[dwOptionalLength] = '\r';
  257. buffer[dwOptionalLength + 1] = '\n';
  258. fsm.m_bExtraCrLf = bExtraCrLf = FALSE;
  259. }
  260. }
  261. fsm.SetFunctionState(FSM_STATE_4);
  262. error = _Socket->Send(buffer, length, SF_INDICATE);
  263. }
  264. //
  265. // fall through
  266. //
  267. case FSM_STATE_4:
  268. //
  269. // Here we also add an extra CR-LF if the app is sending data (even if
  270. // the amount of data supplied is zero) unless we are using a keep-alive
  271. // connection, in which case we're not dealing with old servers which
  272. // require CR-LF at the end of post data.
  273. //
  274. // But only do this for non-HTTP 1.1 servers and proxies ( ie when
  275. // the user puts us in HTTP 1.0 mode)
  276. //
  277. if ((error == ERROR_SUCCESS) && bExtraCrLf) {
  278. fsm.SetFunctionState(FSM_STATE_5);
  279. error = _Socket->Send(gszCRLF, 2, SF_INDICATE);
  280. }
  281. //
  282. // fall through
  283. //
  284. case FSM_STATE_5:
  285. //
  286. // we are now in receiving state
  287. //
  288. if (error == ERROR_SUCCESS) {
  289. SetState(HttpRequestStateResponse);
  290. }
  291. break;
  292. }
  293. quit:
  294. if (error != ERROR_IO_PENDING) {
  295. //dprintf("HTTP connect-send took %d msec\n", GetTickCount() - _dwQuerySetCookieHeader);
  296. fsm.SetDone();
  297. PERF_LEAVE(SendRequest_Fsm);
  298. }
  299. DEBUG_LEAVE(error);
  300. return error;
  301. }