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.

318 lines
9.5 KiB

  1. #include <wininetp.h>
  2. #include "download.h"
  3. static const int EntryInfoSize = 8192;
  4. HINTERNET hDownload = NULL;
  5. struct HandlePair {
  6. HANDLE hConnect;
  7. HANDLE hRequest;
  8. HandlePair(HANDLE hc=NULL, HANDLE hr=NULL) :
  9. hConnect(hc), hRequest(hr) { }
  10. };
  11. bool initialize() {
  12. if (!hDownload) {
  13. hDownload = InternetOpen(NULL,
  14. INTERNET_OPEN_TYPE_PRECONFIG,
  15. NULL, NULL,
  16. 0);
  17. }
  18. return (hDownload!=NULL);
  19. }
  20. /* Determine local file corresponding to request handle
  21. this is the file holding the data downloaded from the network.
  22. typically its an entry in the URL cache. for non-cacheable responses
  23. WININET creates a temporary file. */
  24. int getLocalFile(HANDLE hRequest, LPTSTR pLocalPath, unsigned long dwPathSize) {
  25. *pLocalPath = '\0';
  26. return InternetQueryOption(hRequest, INTERNET_OPTION_DATAFILE_NAME , pLocalPath, &dwPathSize);
  27. }
  28. /* Determine final URL (after redirects) */
  29. int getFinalURL(HANDLE hRequest, LPTSTR pszFinalURL, unsigned long cCharacters) {
  30. *pszFinalURL = '\0';
  31. return InternetQueryOption(hRequest, INTERNET_OPTION_URL, pszFinalURL, &cCharacters);
  32. }
  33. /* returns the Expiry: header from HTTP response */
  34. FILETIME getExpiryHeader(HANDLE hRequest) {
  35. SYSTEMTIME st;
  36. FILETIME ft = {0x0, 0x0};
  37. DWORD dwIndex = 0;
  38. DWORD cbBuffer = sizeof(st);
  39. if (HttpQueryInfo(hRequest, HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME,
  40. &st, &cbBuffer, &dwIndex))
  41. SystemTimeToFileTime(&st, &ft);
  42. return ft;
  43. }
  44. HandlePair createRequest(P3PCURL pszLocation) {
  45. /* P3P downloads are executed with this combination of flags. */
  46. const DWORD glDownloadFlags =
  47. INTERNET_FLAG_NEED_FILE | // Require local copy of file for parsing
  48. INTERNET_FLAG_KEEP_CONNECTION| // No authentication-- policy looks up MUST be anonymous
  49. INTERNET_FLAG_NO_COOKIES | // No cookies -- same reason.
  50. INTERNET_FLAG_RESYNCHRONIZE | // Check for fresh content
  51. INTERNET_FLAG_PRAGMA_NOCACHE; // For intermediary HTTP caches
  52. char achCanonicalForm[URL_LIMIT];
  53. unsigned long cflen = sizeof(achCanonicalForm);
  54. InternetCanonicalizeUrl(pszLocation, achCanonicalForm, &cflen, 0);
  55. char achFilePath[URL_LIMIT] = "";
  56. char achServerName[INTERNET_MAX_HOST_NAME_LENGTH] = "";
  57. URL_COMPONENTS uc = { sizeof(uc) };
  58. uc.lpszHostName = achServerName;
  59. uc.dwHostNameLength = sizeof(achServerName);
  60. uc.lpszUrlPath = achFilePath;
  61. uc.dwUrlPathLength = sizeof(achFilePath);
  62. if (!InternetCrackUrl(achCanonicalForm, 0, 0, &uc))
  63. return NULL;
  64. HINTERNET hConnect, hRequest;
  65. hConnect = InternetConnect(hDownload,
  66. achServerName,
  67. uc.nPort,
  68. NULL, NULL,
  69. INTERNET_SERVICE_HTTP,
  70. 0, 0);
  71. DWORD dwFlags = glDownloadFlags;
  72. if (uc.nScheme==INTERNET_SCHEME_HTTPS)
  73. dwFlags |= INTERNET_FLAG_SECURE;
  74. hRequest = HttpOpenRequest(hConnect, NULL,
  75. achFilePath,
  76. NULL, NULL, NULL,
  77. dwFlags,
  78. 0);
  79. return HandlePair(hConnect, hRequest);
  80. }
  81. unsigned long beginDownload(HANDLE hRequest) {
  82. BOOL fSuccess = HttpSendRequest(hRequest, NULL, 0, NULL, 0);
  83. if (!fSuccess)
  84. return HTTP_STATUS_NOT_FOUND;
  85. /* determine HTTP status code */
  86. unsigned long dwStatusCode = HTTP_STATUS_NOT_FOUND;
  87. unsigned long dwIndex = 0;
  88. unsigned long dwSpace = sizeof(dwStatusCode);
  89. HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  90. (void*) &dwStatusCode, &dwSpace, &dwIndex);
  91. return dwStatusCode;
  92. }
  93. int readResponse(HANDLE hRequest) {
  94. int total = 0;
  95. unsigned long bytesRead;
  96. char buffer[256];
  97. /* This loop downloads the file to HTTP cache.
  98. Because of WININET specs the loop needs to continue until "bytesRead" is zero,
  99. at which point the file will be committed to the cache */
  100. do {
  101. bytesRead = 0;
  102. InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead);
  103. total += bytesRead;
  104. }
  105. while (bytesRead);
  106. return total;
  107. }
  108. void endDownload(HANDLE hConnect) {
  109. if (hConnect)
  110. InternetCloseHandle(hConnect);
  111. }
  112. // Download given URL into local file
  113. int downloadToCache(P3PCURL pszLocation, ResourceInfo *pInfo,
  114. HANDLE *phConnect,
  115. P3PRequest *pRequest) {
  116. static bool fReady = initialize();
  117. HandlePair hndpair = createRequest(pszLocation);
  118. HINTERNET hConnect = hndpair.hConnect;
  119. HINTERNET hRequest = hndpair.hRequest;
  120. /* Give the connect handle back to client.
  121. WININET closes all derived handles when a parent handle is closed.
  122. Client calls endDownload() when done processing the file, which causes
  123. connect handle to be closed, which in turn closes actual request handle */
  124. if (phConnect)
  125. *phConnect = hConnect;
  126. if (!hConnect || !hRequest)
  127. return -1;
  128. if (pRequest)
  129. pRequest->enterIOBoundState();
  130. int total = -1;
  131. unsigned long dwStatusCode = beginDownload(hRequest);
  132. /* status code different from 200-OK is failure */
  133. if (dwStatusCode==HTTP_STATUS_OK) {
  134. total = readResponse(hRequest);
  135. if (total>0 && pInfo) {
  136. getFinalURL(hRequest, pInfo->pszFinalURL, pInfo->cbURL);
  137. getLocalFile(hRequest, pInfo->pszLocalPath, pInfo->cbPath);
  138. pInfo->ftExpiryDate = getExpiryHeader(hRequest);
  139. }
  140. }
  141. if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) {
  142. DWORD dwRetval;
  143. DWORD dwError;
  144. DWORD dwStatusLength = sizeof(DWORD);
  145. DWORD dwIndex = 0;
  146. BOOL fDone;
  147. fDone = FALSE;
  148. while (!fDone)
  149. {
  150. dwRetval = InternetErrorDlg(GetDesktopWindow(),
  151. hRequest,
  152. ERROR_INTERNET_INCORRECT_PASSWORD,
  153. 0L,
  154. NULL);
  155. if (dwRetval == ERROR_INTERNET_FORCE_RETRY) // User pressed ok on credentials dialog
  156. { // Resend request, new credentials are cached and will be replayed by HSR()
  157. if (!HttpSendRequest(hRequest,NULL, 0L, NULL, NULL))
  158. {
  159. dwError = GetLastError();
  160. total = -1;
  161. goto cleanup;
  162. }
  163. dwStatusCode = 0;
  164. if (!HttpQueryInfo(hRequest,
  165. HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
  166. &dwStatusCode,
  167. &dwStatusLength,
  168. &dwIndex))
  169. {
  170. dwError = GetLastError();
  171. total = -1;
  172. goto cleanup;
  173. }
  174. if ((dwStatusCode != HTTP_STATUS_DENIED) && (dwStatusCode != HTTP_STATUS_PROXY_AUTH_REQ))
  175. {
  176. fDone = TRUE;
  177. }
  178. }
  179. else // User pressed cancel from dialog (note ERROR_SUCCESS == ERROR_CANCELLED from IED())
  180. {
  181. fDone = TRUE;
  182. }
  183. }
  184. }
  185. cleanup:
  186. if (pRequest)
  187. pRequest->leaveIOBoundState();
  188. return total;
  189. }
  190. /*
  191. Set relative/absolute expiration on given URL.
  192. The expiration is derived from the string representation in 2nd parameter
  193. and returned via the out parameter.
  194. */
  195. int setExpiration(P3PCURL pszResource, const char *pszExpDate, BOOL fRelative, FILETIME *pftExpires) {
  196. BOOL success;
  197. SYSTEMTIME st;
  198. if (fRelative) {
  199. union {
  200. FILETIME ftAbsExpiry;
  201. unsigned __int64 qwAbsExpiry;
  202. };
  203. int maxAgeSeconds = atoi(pszExpDate);
  204. INTERNET_CACHE_ENTRY_INFO *pInfo = (INTERNET_CACHE_ENTRY_INFO*) new char[EntryInfoSize];
  205. unsigned long cBytes = EntryInfoSize;
  206. memset(pInfo, 0, cBytes);
  207. pInfo->dwStructSize = cBytes;
  208. /* if we cant get last-sync time from the cache we will
  209. "fabricate" it by taking current client clock */
  210. if (GetUrlCacheEntryInfo(pszResource, pInfo, &cBytes))
  211. ftAbsExpiry = pInfo->LastSyncTime;
  212. else
  213. GetSystemTimeAsFileTime(&ftAbsExpiry);
  214. qwAbsExpiry += (unsigned __int64) maxAgeSeconds * 10000000;
  215. success = setExpiration(pszResource, ftAbsExpiry);
  216. *pftExpires = ftAbsExpiry;
  217. delete [] (char*) pInfo;
  218. }
  219. else if (InternetTimeToSystemTime(pszExpDate, &st, 0)) {
  220. SystemTimeToFileTime(&st, pftExpires);
  221. success = setExpiration(pszResource, *pftExpires);
  222. }
  223. return success;
  224. }
  225. /* Set absolute expiry on given URL */
  226. int setExpiration(P3PCURL pszResource, FILETIME ftExpire) {
  227. INTERNET_CACHE_ENTRY_INFO ceInfo;
  228. memset(&ceInfo, 0, sizeof(ceInfo));
  229. ceInfo.dwStructSize = sizeof(ceInfo);
  230. ceInfo.ExpireTime = ftExpire;
  231. BOOL fRet = SetUrlCacheEntryInfo(pszResource, &ceInfo, CACHE_ENTRY_EXPTIME_FC);
  232. return fRet;
  233. }
  234. /* Comparison operator for FILETIME structures */
  235. bool operator > (const FILETIME &ftA, const FILETIME &ftB) {
  236. return (ftA.dwHighDateTime>ftB.dwHighDateTime) ||
  237. (ftA.dwHighDateTime==ftB.dwHighDateTime &&
  238. ftA.dwLowDateTime>ftB.dwHighDateTime);
  239. }