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.

547 lines
13 KiB

  1. #include "stdafx.h"
  2. #include <malloc.h>
  3. #if !defined(BITS_V12_ON_NT4)
  4. #include "request.tmh"
  5. #endif
  6. CBitsCommandRequest::CBitsCommandRequest(
  7. URL_INFO * UrlInfo
  8. ) : m_UrlInfo( UrlInfo ),
  9. m_hRequest( 0 )
  10. {
  11. THROW_HRESULT( OpenHttpRequest( L"BITS_POST", L"HTTP/1.1", *UrlInfo, &m_hRequest ));
  12. }
  13. CBitsCommandRequest::~CBitsCommandRequest()
  14. {
  15. InternetCloseHandle(m_hRequest);
  16. }
  17. void
  18. CBitsCommandRequest::AddContentName(
  19. StringHandle FullPath
  20. )
  21. {
  22. wchar_t Template[] = L"Content-Name: %s\r\n";
  23. StringHandle DirectoryName;
  24. StringHandle FileName;
  25. DirectoryName = BITSCrackFileName( FullPath, FileName );
  26. size_t Length = RTL_NUMBER_OF(Template) + wcslen(FileName);
  27. CAutoString Header ( new wchar_t[ Length ] );
  28. THROW_HRESULT( StringCchPrintf( Header.get(), Length, Template, LPCWSTR(FileName) ));
  29. // add the header
  30. if (!HttpAddRequestHeaders(m_hRequest,
  31. Header.get(),
  32. -1L,
  33. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ))
  34. {
  35. ThrowLastError();
  36. }
  37. }
  38. void
  39. CBitsCommandRequest::AddPacketType(
  40. wchar_t * type
  41. )
  42. {
  43. LogDl("upload: adding packet type '%S'", type );
  44. //
  45. // Assemble the header.
  46. //
  47. wchar_t Template[] = _T("BITS-Packet-Type: %s\r\n");
  48. size_t Length = RTL_NUMBER_OF(Template) + wcslen(type);
  49. CAutoString Header ( new wchar_t[ Length ] );
  50. THROW_HRESULT( StringCchPrintf( Header.get(), Length, Template, type ));
  51. // add the header
  52. if (!HttpAddRequestHeaders(m_hRequest,
  53. Header.get(),
  54. -1L,
  55. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ))
  56. {
  57. ThrowLastError();
  58. }
  59. }
  60. void
  61. CBitsCommandRequest::AddContentRange(
  62. UINT64 RangeStart,
  63. UINT64 RangeEnd,
  64. UINT64 Size
  65. )
  66. {
  67. wchar_t Template[] = _T("Content-Range: bytes %I64u-%I64u/%I64u\r\n");
  68. size_t Length = RTL_NUMBER_OF(Template) + INT64_DIGITS + INT64_DIGITS + INT64_DIGITS;
  69. CAutoString header ( new wchar_t[ Length ] );
  70. THROW_HRESULT( StringCchPrintf( header.get(), Length, Template, RangeStart, RangeEnd, Size ));
  71. if (!HttpAddRequestHeaders(m_hRequest,
  72. header.get(),
  73. -1L,
  74. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ))
  75. {
  76. ThrowLastError();
  77. }
  78. }
  79. void
  80. CBitsCommandRequest::AddSessionId(
  81. StringHandle & id
  82. )
  83. {
  84. //
  85. // Assemble the header.
  86. //
  87. wchar_t Template[] = _T("BITS-Session-Id: %s\r\n");
  88. size_t Length = RTL_NUMBER_OF(Template) + wcslen(id);
  89. CAutoString header ( new wchar_t[ Length ] );
  90. THROW_HRESULT( StringCchPrintf( header.get(), Length, Template, LPCWSTR(id) ));
  91. if (!HttpAddRequestHeaders(m_hRequest,
  92. header.get(),
  93. -1L,
  94. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ))
  95. {
  96. ThrowLastError();
  97. }
  98. }
  99. void
  100. CBitsCommandRequest::AddSupportedProtocols()
  101. {
  102. wchar_t header[] = L"BITS-Supported-Protocols: {7df0354d-249b-430f-820d-3d2a9bef4931}\r\n";
  103. // add the header
  104. if (!HttpAddRequestHeaders(m_hRequest,
  105. header,
  106. -1L,
  107. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ))
  108. {
  109. ThrowLastError();
  110. }
  111. }
  112. // Upload Protocol ID: {7df0354d-249b-430f-820d-3d2a9bef4931}
  113. // DEFINE_GUID(UploadProtocolId,0x7df0354d,0x249b,0x430f,0x82,0x0d,0x3d,0x2a,0x9b,0xef,0x49,0x31);
  114. static const GUID UploadProtocolId =
  115. { 0x7df0354d, 0x249b, 0x430f, {0x82, 0x0d, 0x3d, 0x2a, 0x9b, 0xef, 0x49, 0x31} };
  116. HRESULT
  117. CBitsCommandRequest::CheckResponseProtocol( GUID *pGuid )
  118. {
  119. HRESULT hr = S_OK;
  120. if (!IsEqualGUID(*pGuid,UploadProtocolId))
  121. {
  122. hr = BG_E_CLIENT_SERVER_PROTOCOL_MISMATCH;
  123. }
  124. return hr;
  125. }
  126. DWORD
  127. CBitsCommandRequest::Send(
  128. CAbstractDataReader * Reader
  129. )
  130. {
  131. bool bNeedLock;
  132. try
  133. {
  134. ReleaseWriteLock( bNeedLock );
  135. //
  136. // Send the request, and read the reply code.
  137. //
  138. THROW_HRESULT( SendRequest( m_hRequest, m_UrlInfo, Reader ));
  139. DWORD dwStatus;
  140. {
  141. DWORD dwLength;
  142. dwLength = sizeof(dwStatus);
  143. if (! HttpQueryInfo(m_hRequest,
  144. HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  145. (LPVOID)&dwStatus,
  146. &dwLength,
  147. NULL))
  148. {
  149. ThrowLastError();
  150. }
  151. }
  152. if (dwStatus == 200 ||
  153. dwStatus == 201)
  154. {
  155. THROW_HRESULT( CheckReplyPacketType() );
  156. }
  157. DrainReply();
  158. ReclaimWriteLock( bNeedLock );
  159. return dwStatus;
  160. }
  161. catch ( ComError err )
  162. {
  163. ReclaimWriteLock( bNeedLock );
  164. throw;
  165. }
  166. }
  167. void
  168. CBitsCommandRequest::DrainReply()
  169. /*
  170. Server replies often contain an entity body even though BITS did not ask for one.
  171. For example, a 404 error may be accompanied by HTML explaining how to contact the
  172. system administrator. BITS needs to read all of the reply entity body before sending
  173. the next request on the HTTP connection, or it will read data instead of headers after
  174. the next request.
  175. */
  176. {
  177. //
  178. // Look for a length header.
  179. //
  180. HRESULT hr;
  181. UINT64 Length;
  182. hr = GetContentLength( &Length );
  183. if (hr == BG_E_HEADER_NOT_FOUND)
  184. {
  185. //
  186. // If a content length is not specified, then the response may be in chunked encoding,
  187. // terminated by a connection close, or invalid. In those cases, the client won't be reading
  188. // more from this connection anyway, so reading all the data is not necessary.
  189. //
  190. return;
  191. }
  192. THROW_HRESULT( hr );
  193. //
  194. // drain the pipe.
  195. //
  196. DWORD BytesRead;
  197. while ( Length > 0 )
  198. {
  199. if (!InternetReadFile( m_hRequest,
  200. g_FileDataBuffer,
  201. FILE_DATA_BUFFER_LEN,
  202. &BytesRead
  203. ))
  204. {
  205. LogWarning("read failed %d", GetLastError() );
  206. break;
  207. }
  208. Length -= BytesRead;
  209. if (BytesRead == 0)
  210. {
  211. // graceful closure
  212. return;
  213. }
  214. }
  215. return;
  216. }
  217. HRESULT
  218. CBitsCommandRequest::GetServerRange(
  219. UINT64 * RangeEnd
  220. )
  221. {
  222. const wchar_t Name[] = L"BITS-Received-Content-Range";
  223. wchar_t Header[ INT64_DIGITS+1 ];
  224. RETURN_HRESULT( GetMandatoryHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  225. // parse the data
  226. if (1 != _stscanf( Header, _T("%I64u"), RangeEnd ))
  227. {
  228. return BG_E_INVALID_SERVER_RESPONSE;
  229. }
  230. LogInfo("content range: %I64u", *RangeEnd );
  231. return S_OK;
  232. }
  233. HRESULT
  234. CBitsCommandRequest::GetContentLength(
  235. UINT64 * Length
  236. )
  237. {
  238. *Length = 0;
  239. wchar_t Header[INT64_DIGITS+1];
  240. RETURN_HRESULT( GetOptionalHeaderCb( WINHTTP_QUERY_CONTENT_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, Header, sizeof(Header), __LINE__));
  241. if ( 1 != swscanf( Header, L"%I64u", Length ) )
  242. {
  243. return BG_E_INVALID_SERVER_RESPONSE;
  244. }
  245. LogInfo("Content-Length was %I64u", *Length );
  246. return S_OK;
  247. }
  248. HRESULT
  249. CBitsCommandRequest::GetProtocol(
  250. GUID * id
  251. )
  252. {
  253. const wchar_t Name[] = L"BITS-Protocol";
  254. wchar_t Header[ MAX_GUID_CHARS ];
  255. RETURN_HRESULT( GetMandatoryHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  256. HRESULT hr = IIDFromString( Header, id );
  257. if (hr == E_INVALIDARG)
  258. {
  259. hr = BG_E_INVALID_SERVER_RESPONSE;
  260. }
  261. return hr;
  262. }
  263. HRESULT
  264. CBitsCommandRequest::GetSessionId(
  265. StringHandle * id
  266. )
  267. {
  268. const wchar_t Name[] = L"BITS-Session-Id";
  269. wchar_t Header[ MAX_SESSION_ID ];
  270. RETURN_HRESULT( GetMandatoryHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  271. try
  272. {
  273. // this may throw an out-of-memory exception
  274. //
  275. *id = Header;
  276. }
  277. catch ( ComError err )
  278. {
  279. return err.Error();
  280. }
  281. return S_OK;
  282. }
  283. HRESULT
  284. CBitsCommandRequest::CheckReplyPacketType()
  285. {
  286. const wchar_t Name[] = L"BITS-Packet-Type";
  287. wchar_t Header[ MAX_PACKET_TYPE ];
  288. RETURN_HRESULT( GetMandatoryHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  289. if (0 != _wcsicmp( Header, L"Ack"))
  290. {
  291. return BG_E_INVALID_SERVER_RESPONSE;
  292. }
  293. return S_OK;
  294. }
  295. HRESULT
  296. CBitsCommandRequest::GetBitsError(
  297. HRESULT * phr
  298. )
  299. {
  300. const wchar_t Name[] = L"BITS-Error";
  301. wchar_t Header[ INT_DIGITS+3+1 ]; // allow space for "0x" prefix and negative sign - in case we later allow those
  302. RETURN_HRESULT( GetOptionalHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  303. LogWarning("BITS-Error was '%S'", Header );
  304. // parse the data
  305. if (1 != _stscanf( Header, _T("0x%x"), phr ))
  306. {
  307. return BG_E_INVALID_SERVER_RESPONSE;
  308. }
  309. return S_OK;
  310. }
  311. HRESULT
  312. CBitsCommandRequest::GetBitsErrorContext(
  313. DWORD * pdw
  314. )
  315. {
  316. const wchar_t Name[] = L"BITS-Error-Context";
  317. wchar_t Header[ INT_DIGITS+1 ];
  318. RETURN_HRESULT( GetOptionalHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__));
  319. LogWarning("BITS-Error-Context was '%S'", Header );
  320. // parse the data
  321. if (1 != _stscanf( Header, _T("0x%x"), pdw ) ||
  322. (*pdw != BG_ERROR_CONTEXT_REMOTE_FILE && *pdw != BG_ERROR_CONTEXT_REMOTE_APPLICATION))
  323. {
  324. return BG_E_INVALID_SERVER_RESPONSE;
  325. }
  326. return S_OK;
  327. }
  328. HRESULT
  329. CBitsCommandRequest::GetReplyUrl(
  330. CAutoString & ReplyUrl
  331. )
  332. {
  333. const wchar_t Name[] = L"BITS-Reply-Url";
  334. HRESULT hr = GetRequestHeader( m_hRequest, HTTP_QUERY_CUSTOM, Name, ReplyUrl, INTERNET_MAX_URL_LENGTH );
  335. if (hr == S_FALSE)
  336. {
  337. return BG_E_HEADER_NOT_FOUND;
  338. }
  339. return hr;
  340. }
  341. HRESULT
  342. CBitsCommandRequest::GetHostId(
  343. StringHandle * pstr
  344. )
  345. {
  346. *pstr = StringHandle();
  347. CAutoString Value;
  348. const wchar_t Name[] = L"BITS-Host-Id";
  349. HRESULT hr = GetRequestHeader( m_hRequest, HTTP_QUERY_CUSTOM, Name, Value, MAX_HOST_ID );
  350. if (hr == S_FALSE)
  351. {
  352. return S_OK;
  353. }
  354. if (hr != S_OK)
  355. {
  356. return hr;
  357. }
  358. //
  359. // The StringHandle will copy Value.get() instead of taking ownership of it,
  360. // so this fn still needs to delete the original.
  361. //
  362. *pstr = Value.get();
  363. return S_OK;
  364. }
  365. HRESULT
  366. CBitsCommandRequest::GetHostIdFallbackTimeout(
  367. DWORD * pVal
  368. )
  369. {
  370. *pVal = 0xFFFFFFFF;
  371. const wchar_t * Name = L"BITS-Host-Id-Fallback-Timeout";
  372. wchar_t Header[ INT_DIGITS+1 ];
  373. HRESULT hr = GetOptionalHeaderCb( WINHTTP_QUERY_CUSTOM, Name, Header, sizeof(Header), __LINE__);
  374. if (hr == BG_E_HEADER_NOT_FOUND)
  375. {
  376. return S_OK;
  377. }
  378. if (FAILED(hr))
  379. {
  380. return hr;
  381. }
  382. if ( !swscanf( Header, L"%u", pVal ) )
  383. return BG_E_INVALID_SERVER_RESPONSE;
  384. return S_OK;
  385. }
  386. HRESULT
  387. CBitsCommandRequest::GetOptionalHeaderCb(
  388. DWORD dwInfoLevel,
  389. LPCWSTR Name,
  390. LPWSTR Value,
  391. DWORD ValueBytes,
  392. DWORD Line
  393. )
  394. {
  395. if (WinHttpQueryHeaders( m_hRequest,
  396. dwInfoLevel,
  397. Name,
  398. Value,
  399. &ValueBytes,
  400. WINHTTP_NO_HEADER_INDEX
  401. ))
  402. {
  403. return S_OK;
  404. }
  405. DWORD s = GetLastError();
  406. if (s == ERROR_INSUFFICIENT_BUFFER)
  407. {
  408. LogError("line %d: header is too large", Line);
  409. return BG_E_INVALID_SERVER_RESPONSE;
  410. }
  411. // note that BG_E_HEADER_NOT_FOUND is the same as HRESULT_FROM_WIN32(ERROR_WINHTTP_HEADER_NOT_FOUND)
  412. return HRESULT_FROM_WIN32( s );
  413. }
  414. HRESULT
  415. CBitsCommandRequest::GetMandatoryHeaderCb(
  416. DWORD dwInfoLevel,
  417. LPCWSTR Name,
  418. LPWSTR Value,
  419. DWORD ValueBytes,
  420. DWORD Line
  421. )
  422. {
  423. HRESULT hr;
  424. hr = GetOptionalHeaderCb( dwInfoLevel, Name, Value, ValueBytes, Line );
  425. if (hr == BG_E_HEADER_NOT_FOUND)
  426. {
  427. LogError("line %d: header not present", Line);
  428. return BG_E_INVALID_SERVER_RESPONSE;
  429. }
  430. return hr;
  431. }